Skip to main content

llama_cpp_bindings/
error.rs

1use std::ffi::NulError;
2use std::num::NonZeroI32;
3use std::os::raw::c_int;
4use std::path::PathBuf;
5use std::string::FromUtf8Error;
6
7use crate::llama_batch::BatchAddError;
8
9/// A failable result from a llama.cpp function.
10pub type Result<TValue> = std::result::Result<TValue, LlamaCppError>;
11
12/// All errors that can occur in the llama-cpp crate.
13#[derive(Debug, Eq, PartialEq, thiserror::Error)]
14pub enum LlamaCppError {
15    /// The backend was already initialized. This can generally be ignored as initializing the backend
16    /// is idempotent.
17    #[error("BackendAlreadyInitialized")]
18    BackendAlreadyInitialized,
19    /// There was an error while get the chat template from model.
20    #[error("{0}")]
21    ChatTemplateError(#[from] ChatTemplateError),
22    /// There was an error while decoding a batch.
23    #[error("{0}")]
24    DecodeError(#[from] DecodeError),
25    /// There was an error while encoding a batch.
26    #[error("{0}")]
27    EncodeError(#[from] EncodeError),
28    /// There was an error loading a model.
29    #[error("{0}")]
30    LlamaModelLoadError(#[from] LlamaModelLoadError),
31    /// There was an error creating a new model context.
32    #[error("{0}")]
33    LlamaContextLoadError(#[from] LlamaContextLoadError),
34    /// There was an error adding a token to a batch.
35    #[error["{0}"]]
36    BatchAddError(#[from] BatchAddError),
37    /// see [`EmbeddingsError`]
38    #[error(transparent)]
39    EmbeddingError(#[from] EmbeddingsError),
40    // See [`LlamaSamplerError`]
41    /// Backend device not found
42    #[error("Backend device {0} not found")]
43    BackendDeviceNotFound(usize),
44    /// Max devices exceeded
45    #[error("Max devices exceeded. Max devices is {0}")]
46    MaxDevicesExceeded(usize),
47    /// Failed to convert JSON schema to grammar.
48    #[error("JsonSchemaToGrammarError: {0}")]
49    JsonSchemaToGrammarError(String),
50}
51
52/// There was an error while getting the chat template from a model.
53#[derive(Debug, Eq, PartialEq, thiserror::Error)]
54pub enum ChatTemplateError {
55    /// gguf has no chat template (by that name)
56    #[error("chat template not found - returned null pointer")]
57    MissingTemplate,
58
59    /// chat template contained a null byte
60    #[error("null byte in string {0}")]
61    NullError(#[from] NulError),
62
63    /// The chat template was not valid utf8.
64    #[error(transparent)]
65    Utf8Error(#[from] std::str::Utf8Error),
66}
67
68/// Failed fetching metadata value
69#[derive(Debug, Eq, PartialEq, thiserror::Error)]
70pub enum MetaValError {
71    /// The provided string contains an unexpected null-byte
72    #[error("null byte in string {0}")]
73    NullError(#[from] NulError),
74
75    /// The returned data contains invalid UTF8 data
76    #[error("FromUtf8Error {0}")]
77    FromUtf8Error(#[from] FromUtf8Error),
78
79    /// Got negative return value. This happens if the key or index queried does not exist.
80    #[error("Negative return value. Likely due to a missing index or key. Got return value: {0}")]
81    NegativeReturn(i32),
82}
83
84/// Failed to Load context
85#[derive(Debug, Eq, PartialEq, thiserror::Error)]
86pub enum LlamaContextLoadError {
87    /// llama.cpp returned null
88    #[error("null reference from llama.cpp")]
89    NullReturn,
90}
91
92/// Failed to decode a batch.
93#[derive(Debug, Eq, PartialEq, thiserror::Error)]
94pub enum DecodeError {
95    /// No kv cache slot was available.
96    #[error("Decode Error 1: NoKvCacheSlot")]
97    NoKvCacheSlot,
98    /// The number of tokens in the batch was 0.
99    #[error("Decode Error -1: n_tokens == 0")]
100    NTokensZero,
101    /// An unknown error occurred.
102    #[error("Decode Error {0}: unknown")]
103    Unknown(c_int),
104}
105
106/// Failed to decode a batch.
107#[derive(Debug, Eq, PartialEq, thiserror::Error)]
108pub enum EncodeError {
109    /// No kv cache slot was available.
110    #[error("Encode Error 1: NoKvCacheSlot")]
111    NoKvCacheSlot,
112    /// The number of tokens in the batch was 0.
113    #[error("Encode Error -1: n_tokens == 0")]
114    NTokensZero,
115    /// An unknown error occurred.
116    #[error("Encode Error {0}: unknown")]
117    Unknown(c_int),
118}
119
120/// When embedding related functions fail
121#[derive(Debug, Eq, PartialEq, thiserror::Error)]
122pub enum EmbeddingsError {
123    /// Embeddings weren't enabled in the context options
124    #[error("Embeddings weren't enabled in the context options")]
125    NotEnabled,
126    /// Logits weren't enabled for the given token
127    #[error("Logits were not enabled for the given token")]
128    LogitsNotEnabled,
129    /// The given sequence index exceeds the max sequence id
130    #[error("Can't use sequence embeddings with a model supporting only LLAMA_POOLING_TYPE_NONE")]
131    NonePoolType,
132    /// The embedding dimension does not fit into a usize.
133    #[error("Invalid embedding dimension: {0}")]
134    InvalidEmbeddingDimension(#[source] std::num::TryFromIntError),
135}
136
137/// When logits-related functions fail
138#[derive(Debug, Eq, PartialEq, thiserror::Error)]
139pub enum LogitsError {
140    /// The logits data pointer is null.
141    #[error("logits data pointer is null")]
142    NullLogits,
143    /// The requested token index has not been initialized for logits.
144    #[error("logit for token index {0} is not initialized")]
145    TokenNotInitialized(i32),
146    /// The token index exceeds the context size.
147    #[error("token index {token_index} exceeds context size {context_size}")]
148    TokenIndexExceedsContext {
149        /// The token index that was requested.
150        token_index: u32,
151        /// The context size.
152        context_size: u32,
153    },
154    /// The vocabulary size does not fit into a usize.
155    #[error("n_vocab does not fit into usize: {0}")]
156    VocabSizeOverflow(#[source] std::num::TryFromIntError),
157    /// The token index does not fit into a u32.
158    #[error("token_index does not fit into u32: {0}")]
159    TokenIndexOverflow(#[source] std::num::TryFromIntError),
160}
161
162/// Errors that can occur when initializing a grammar sampler
163#[derive(Debug, Eq, PartialEq, thiserror::Error)]
164pub enum GrammarError {
165    /// The grammar root was not found in the grammar string
166    #[error("Grammar root not found in grammar string")]
167    RootNotFound,
168    /// The trigger word contains null bytes
169    #[error("Trigger word contains null bytes: {0}")]
170    TriggerWordNullBytes(NulError),
171    /// The grammar string or root contains null bytes
172    #[error("Grammar string or root contains null bytes: {0}")]
173    GrammarNullBytes(NulError),
174    /// A string contains null bytes
175    #[error("String contains null bytes: {0}")]
176    NulError(#[from] NulError),
177    /// The grammar call returned null
178    #[error("Grammar call returned null")]
179    NullGrammar,
180    /// An integer value exceeded the allowed range
181    #[error("Integer overflow: {0}")]
182    IntegerOverflow(String),
183    /// An error from the llguidance library
184    #[error("llguidance error: {0}")]
185    LlguidanceError(String),
186}
187
188/// Errors that can occur when creating a sampling configuration.
189#[derive(Debug, Eq, PartialEq, thiserror::Error)]
190pub enum SamplingError {
191    /// An integer value exceeded the allowed range
192    #[error("Integer overflow: {0}")]
193    IntegerOverflow(String),
194}
195
196/// Decode a error from llama.cpp into a [`DecodeError`].
197impl From<NonZeroI32> for DecodeError {
198    fn from(value: NonZeroI32) -> Self {
199        match value.get() {
200            1 => Self::NoKvCacheSlot,
201            -1 => Self::NTokensZero,
202            error_code => Self::Unknown(error_code),
203        }
204    }
205}
206
207/// Encode a error from llama.cpp into a [`EncodeError`].
208impl From<NonZeroI32> for EncodeError {
209    fn from(value: NonZeroI32) -> Self {
210        match value.get() {
211            1 => Self::NoKvCacheSlot,
212            -1 => Self::NTokensZero,
213            error_code => Self::Unknown(error_code),
214        }
215    }
216}
217
218/// An error that can occur when loading a model.
219#[derive(Debug, Eq, PartialEq, thiserror::Error)]
220pub enum LlamaModelLoadError {
221    /// There was a null byte in a provided string and thus it could not be converted to a C string.
222    #[error("null byte in string {0}")]
223    NullError(#[from] NulError),
224    /// llama.cpp returned a nullptr - this could be many different causes.
225    #[error("null result from llama cpp")]
226    NullResult,
227    /// Failed to convert the path to a rust str. This means the path was not valid unicode
228    #[error("failed to convert path {0} to str")]
229    PathToStrError(PathBuf),
230    /// The model file does not exist at the given path.
231    #[error("model file not found: {0}")]
232    FileNotFound(PathBuf),
233}
234
235/// An error that can occur when loading a model.
236#[derive(Debug, Eq, PartialEq, thiserror::Error)]
237pub enum LlamaLoraAdapterInitError {
238    /// There was a null byte in a provided string and thus it could not be converted to a C string.
239    #[error("null byte in string {0}")]
240    NullError(#[from] NulError),
241    /// llama.cpp returned a nullptr - this could be many different causes.
242    #[error("null result from llama cpp")]
243    NullResult,
244    /// Failed to convert the path to a rust str. This means the path was not valid unicode
245    #[error("failed to convert path {0} to str")]
246    PathToStrError(PathBuf),
247    /// The adapter file does not exist at the given path.
248    #[error("adapter file not found: {0}")]
249    FileNotFound(PathBuf),
250}
251
252/// An error that can occur when loading a model.
253#[derive(Debug, Eq, PartialEq, thiserror::Error)]
254pub enum LlamaLoraAdapterSetError {
255    /// llama.cpp returned a non-zero error code.
256    #[error("error code from llama cpp")]
257    ErrorResult(i32),
258}
259
260/// An error that can occur when loading a model.
261#[derive(Debug, Eq, PartialEq, thiserror::Error)]
262pub enum LlamaLoraAdapterRemoveError {
263    /// llama.cpp returned a non-zero error code.
264    #[error("error code from llama cpp")]
265    ErrorResult(i32),
266}
267
268/// An error that can occur when converting a token to a string.
269#[derive(Debug, thiserror::Error, Clone)]
270#[non_exhaustive]
271pub enum TokenToStringError {
272    /// the token type was unknown
273    #[error("Unknown Token Type")]
274    UnknownTokenType,
275    /// There was insufficient buffer space to convert the token to a string.
276    #[error("Insufficient Buffer Space {0}")]
277    InsufficientBufferSpace(c_int),
278    /// The token was not valid utf8.
279    #[error("FromUtf8Error {0}")]
280    FromUtf8Error(#[from] FromUtf8Error),
281    /// An integer conversion failed.
282    #[error("Integer conversion error: {0}")]
283    IntConversionError(#[from] std::num::TryFromIntError),
284}
285
286/// Failed to convert a string to a token sequence.
287#[derive(Debug, thiserror::Error)]
288pub enum StringToTokenError {
289    /// the string contained a null byte and thus could not be converted to a c string.
290    #[error("{0}")]
291    NulError(#[from] NulError),
292    #[error("{0}")]
293    /// Failed to convert a provided integer to a [`c_int`].
294    CIntConversionError(#[from] std::num::TryFromIntError),
295}
296
297/// Failed to apply model chat template.
298#[derive(Debug, thiserror::Error)]
299pub enum NewLlamaChatMessageError {
300    /// the string contained a null byte and thus could not be converted to a c string.
301    #[error("{0}")]
302    NulError(#[from] NulError),
303}
304
305/// Failed to apply model chat template.
306#[derive(Debug, thiserror::Error)]
307pub enum ApplyChatTemplateError {
308    /// the string contained a null byte and thus could not be converted to a c string.
309    #[error("{0}")]
310    NulError(#[from] NulError),
311    /// the string could not be converted to utf8.
312    #[error("{0}")]
313    FromUtf8Error(#[from] FromUtf8Error),
314    /// llama.cpp returned a null pointer for the template result.
315    #[error("null result from llama.cpp")]
316    NullResult,
317    /// llama.cpp returned an error code.
318    #[error("ffi error {0}")]
319    FfiError(i32),
320    /// invalid grammar trigger data returned by llama.cpp.
321    #[error("invalid grammar trigger data")]
322    InvalidGrammarTriggerType,
323    /// An integer conversion failed.
324    #[error("Integer conversion error: {0}")]
325    IntConversionError(#[from] std::num::TryFromIntError),
326}
327
328/// Failed to parse a chat response.
329#[derive(Debug, thiserror::Error)]
330pub enum ChatParseError {
331    /// the string contained a null byte and thus could not be converted to a c string.
332    #[error("{0}")]
333    NulError(#[from] NulError),
334    /// the string could not be converted to utf8.
335    #[error("{0}")]
336    Utf8Error(#[from] FromUtf8Error),
337    /// llama.cpp returned a null pointer for the parse result.
338    #[error("null result from llama.cpp")]
339    NullResult,
340    /// llama.cpp returned an error code.
341    #[error("ffi error {0}")]
342    FfiError(i32),
343}
344
345/// Failed to accept a token in a sampler.
346#[derive(Debug, thiserror::Error)]
347pub enum SamplerAcceptError {
348    /// llama.cpp returned an error code.
349    #[error("ffi error {0}")]
350    FfiError(i32),
351}
352
353/// Errors that can occur when modifying model parameters.
354#[derive(Debug, Eq, PartialEq, thiserror::Error)]
355pub enum ModelParamsError {
356    /// The internal override vector has no available slot.
357    #[error("No available slot in override vector")]
358    NoAvailableSlot,
359    /// The first override slot is not empty.
360    #[error("Override slot is not empty")]
361    SlotNotEmpty,
362    /// A character in the key is not a valid C char.
363    #[error("Invalid character in key: byte {byte}, {reason}")]
364    InvalidCharacterInKey {
365        /// The byte value that failed conversion.
366        byte: u8,
367        /// The reason the conversion failed.
368        reason: String,
369    },
370}
371
372/// Failed to sample a token from the data array.
373#[derive(Debug, Eq, PartialEq, thiserror::Error)]
374pub enum TokenSamplingError {
375    /// The sampler did not select any token.
376    #[error("No token was selected by the sampler")]
377    NoTokenSelected,
378}
379
380#[cfg(test)]
381mod tests {
382    use std::num::NonZeroI32;
383
384    use super::{DecodeError, EncodeError};
385
386    #[test]
387    fn decode_error_no_kv_cache_slot() {
388        let error = DecodeError::from(NonZeroI32::new(1).expect("1 is non-zero"));
389
390        assert_eq!(error, DecodeError::NoKvCacheSlot);
391        assert_eq!(error.to_string(), "Decode Error 1: NoKvCacheSlot");
392    }
393
394    #[test]
395    fn decode_error_n_tokens_zero() {
396        let error = DecodeError::from(NonZeroI32::new(-1).expect("-1 is non-zero"));
397
398        assert_eq!(error, DecodeError::NTokensZero);
399        assert_eq!(error.to_string(), "Decode Error -1: n_tokens == 0");
400    }
401
402    #[test]
403    fn decode_error_unknown() {
404        let error = DecodeError::from(NonZeroI32::new(42).expect("42 is non-zero"));
405
406        assert_eq!(error, DecodeError::Unknown(42));
407        assert_eq!(error.to_string(), "Decode Error 42: unknown");
408    }
409
410    #[test]
411    fn encode_error_no_kv_cache_slot() {
412        let error = EncodeError::from(NonZeroI32::new(1).expect("1 is non-zero"));
413
414        assert_eq!(error, EncodeError::NoKvCacheSlot);
415        assert_eq!(error.to_string(), "Encode Error 1: NoKvCacheSlot");
416    }
417
418    #[test]
419    fn encode_error_n_tokens_zero() {
420        let error = EncodeError::from(NonZeroI32::new(-1).expect("-1 is non-zero"));
421
422        assert_eq!(error, EncodeError::NTokensZero);
423        assert_eq!(error.to_string(), "Encode Error -1: n_tokens == 0");
424    }
425
426    #[test]
427    fn encode_error_unknown() {
428        let error = EncodeError::from(NonZeroI32::new(99).expect("99 is non-zero"));
429
430        assert_eq!(error, EncodeError::Unknown(99));
431        assert_eq!(error.to_string(), "Encode Error 99: unknown");
432    }
433}