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}
133
134/// Errors that can occur when initializing a grammar sampler
135#[derive(Debug, Eq, PartialEq, thiserror::Error)]
136pub enum GrammarError {
137    /// The grammar root was not found in the grammar string
138    #[error("Grammar root not found in grammar string")]
139    RootNotFound,
140    /// The trigger word contains null bytes
141    #[error("Trigger word contains null bytes")]
142    TriggerWordNullBytes,
143    /// The grammar string or root contains null bytes
144    #[error("Grammar string or root contains null bytes")]
145    GrammarNullBytes,
146    /// A string contains null bytes
147    #[error("String contains null bytes: {0}")]
148    NulError(#[from] std::ffi::NulError),
149    /// The grammar call returned null
150    #[error("Grammar call returned null")]
151    NullGrammar,
152    /// An integer value exceeded the allowed range
153    #[error("Integer overflow: {0}")]
154    IntegerOverflow(String),
155    /// An error from the llguidance library
156    #[error("llguidance error: {0}")]
157    LlguidanceError(String),
158}
159
160/// Errors that can occur when creating a sampling configuration.
161#[derive(Debug, Eq, PartialEq, thiserror::Error)]
162pub enum SamplingError {
163    /// An integer value exceeded the allowed range
164    #[error("Integer overflow: {0}")]
165    IntegerOverflow(String),
166}
167
168/// Decode a error from llama.cpp into a [`DecodeError`].
169impl From<NonZeroI32> for DecodeError {
170    fn from(value: NonZeroI32) -> Self {
171        match value.get() {
172            1 => DecodeError::NoKvCacheSlot,
173            -1 => DecodeError::NTokensZero,
174            error_code => DecodeError::Unknown(error_code),
175        }
176    }
177}
178
179/// Encode a error from llama.cpp into a [`EncodeError`].
180impl From<NonZeroI32> for EncodeError {
181    fn from(value: NonZeroI32) -> Self {
182        match value.get() {
183            1 => EncodeError::NoKvCacheSlot,
184            -1 => EncodeError::NTokensZero,
185            error_code => EncodeError::Unknown(error_code),
186        }
187    }
188}
189
190/// An error that can occur when loading a model.
191#[derive(Debug, Eq, PartialEq, thiserror::Error)]
192pub enum LlamaModelLoadError {
193    /// There was a null byte in a provided string and thus it could not be converted to a C string.
194    #[error("null byte in string {0}")]
195    NullError(#[from] NulError),
196    /// llama.cpp returned a nullptr - this could be many different causes.
197    #[error("null result from llama cpp")]
198    NullResult,
199    /// Failed to convert the path to a rust str. This means the path was not valid unicode
200    #[error("failed to convert path {0} to str")]
201    PathToStrError(PathBuf),
202}
203
204/// An error that can occur when loading a model.
205#[derive(Debug, Eq, PartialEq, thiserror::Error)]
206pub enum LlamaLoraAdapterInitError {
207    /// There was a null byte in a provided string and thus it could not be converted to a C string.
208    #[error("null byte in string {0}")]
209    NullError(#[from] NulError),
210    /// llama.cpp returned a nullptr - this could be many different causes.
211    #[error("null result from llama cpp")]
212    NullResult,
213    /// Failed to convert the path to a rust str. This means the path was not valid unicode
214    #[error("failed to convert path {0} to str")]
215    PathToStrError(PathBuf),
216}
217
218/// An error that can occur when loading a model.
219#[derive(Debug, Eq, PartialEq, thiserror::Error)]
220pub enum LlamaLoraAdapterSetError {
221    /// llama.cpp returned a non-zero error code.
222    #[error("error code from llama cpp")]
223    ErrorResult(i32),
224}
225
226/// An error that can occur when loading a model.
227#[derive(Debug, Eq, PartialEq, thiserror::Error)]
228pub enum LlamaLoraAdapterRemoveError {
229    /// llama.cpp returned a non-zero error code.
230    #[error("error code from llama cpp")]
231    ErrorResult(i32),
232}
233
234/// An error that can occur when converting a token to a string.
235#[derive(Debug, thiserror::Error, Clone)]
236#[non_exhaustive]
237pub enum TokenToStringError {
238    /// the token type was unknown
239    #[error("Unknown Token Type")]
240    UnknownTokenType,
241    /// There was insufficient buffer space to convert the token to a string.
242    #[error("Insufficient Buffer Space {0}")]
243    InsufficientBufferSpace(c_int),
244    /// The token was not valid utf8.
245    #[error("FromUtf8Error {0}")]
246    FromUtf8Error(#[from] FromUtf8Error),
247}
248
249/// Failed to convert a string to a token sequence.
250#[derive(Debug, thiserror::Error)]
251pub enum StringToTokenError {
252    /// the string contained a null byte and thus could not be converted to a c string.
253    #[error("{0}")]
254    NulError(#[from] NulError),
255    #[error("{0}")]
256    /// Failed to convert a provided integer to a [`c_int`].
257    CIntConversionError(#[from] std::num::TryFromIntError),
258}
259
260/// Failed to apply model chat template.
261#[derive(Debug, thiserror::Error)]
262pub enum NewLlamaChatMessageError {
263    /// the string contained a null byte and thus could not be converted to a c string.
264    #[error("{0}")]
265    NulError(#[from] NulError),
266}
267
268/// Failed to apply model chat template.
269#[derive(Debug, thiserror::Error)]
270pub enum ApplyChatTemplateError {
271    /// the string contained a null byte and thus could not be converted to a c string.
272    #[error("{0}")]
273    NulError(#[from] NulError),
274    /// the string could not be converted to utf8.
275    #[error("{0}")]
276    FromUtf8Error(#[from] FromUtf8Error),
277    /// llama.cpp returned a null pointer for the template result.
278    #[error("null result from llama.cpp")]
279    NullResult,
280    /// llama.cpp returned an error code.
281    #[error("ffi error {0}")]
282    FfiError(i32),
283    /// invalid grammar trigger data returned by llama.cpp.
284    #[error("invalid grammar trigger data")]
285    InvalidGrammarTriggerType,
286}
287
288/// Failed to parse a chat response.
289#[derive(Debug, thiserror::Error)]
290pub enum ChatParseError {
291    /// the string contained a null byte and thus could not be converted to a c string.
292    #[error("{0}")]
293    NulError(#[from] NulError),
294    /// the string could not be converted to utf8.
295    #[error("{0}")]
296    Utf8Error(#[from] FromUtf8Error),
297    /// llama.cpp returned a null pointer for the parse result.
298    #[error("null result from llama.cpp")]
299    NullResult,
300    /// llama.cpp returned an error code.
301    #[error("ffi error {0}")]
302    FfiError(i32),
303}
304
305/// Failed to accept a token in a sampler.
306#[derive(Debug, thiserror::Error)]
307pub enum SamplerAcceptError {
308    /// llama.cpp returned an error code.
309    #[error("ffi error {0}")]
310    FfiError(i32),
311}
312
313/// Errors that can occur when modifying model parameters.
314#[derive(Debug, Eq, PartialEq, thiserror::Error)]
315pub enum ModelParamsError {
316    /// The internal override vector has no available slot.
317    #[error("No available slot in override vector")]
318    NoAvailableSlot,
319    /// The first override slot is not empty.
320    #[error("Override slot is not empty")]
321    SlotNotEmpty,
322    /// A character in the key is not a valid C char.
323    #[error("Invalid character in key: byte {byte}, {reason}")]
324    InvalidCharacterInKey {
325        /// The byte value that failed conversion.
326        byte: u8,
327        /// The reason the conversion failed.
328        reason: String,
329    },
330}
331
332/// Failed to sample a token from the data array.
333#[derive(Debug, Eq, PartialEq, thiserror::Error)]
334pub enum TokenSamplingError {
335    /// The sampler did not select any token.
336    #[error("No token was selected by the sampler")]
337    NoTokenSelected,
338}
339
340#[cfg(test)]
341mod tests {
342    use std::num::NonZeroI32;
343
344    use super::{DecodeError, EncodeError};
345
346    #[test]
347    fn decode_error_no_kv_cache_slot() {
348        let error = DecodeError::from(NonZeroI32::new(1).expect("1 is non-zero"));
349
350        assert_eq!(error, DecodeError::NoKvCacheSlot);
351        assert_eq!(error.to_string(), "Decode Error 1: NoKvCacheSlot");
352    }
353
354    #[test]
355    fn decode_error_n_tokens_zero() {
356        let error = DecodeError::from(NonZeroI32::new(-1).expect("-1 is non-zero"));
357
358        assert_eq!(error, DecodeError::NTokensZero);
359        assert_eq!(error.to_string(), "Decode Error -1: n_tokens == 0");
360    }
361
362    #[test]
363    fn decode_error_unknown() {
364        let error = DecodeError::from(NonZeroI32::new(42).expect("42 is non-zero"));
365
366        assert_eq!(error, DecodeError::Unknown(42));
367        assert_eq!(error.to_string(), "Decode Error 42: unknown");
368    }
369
370    #[test]
371    fn encode_error_no_kv_cache_slot() {
372        let error = EncodeError::from(NonZeroI32::new(1).expect("1 is non-zero"));
373
374        assert_eq!(error, EncodeError::NoKvCacheSlot);
375        assert_eq!(error.to_string(), "Encode Error 1: NoKvCacheSlot");
376    }
377
378    #[test]
379    fn encode_error_n_tokens_zero() {
380        let error = EncodeError::from(NonZeroI32::new(-1).expect("-1 is non-zero"));
381
382        assert_eq!(error, EncodeError::NTokensZero);
383        assert_eq!(error.to_string(), "Encode Error -1: n_tokens == 0");
384    }
385
386    #[test]
387    fn encode_error_unknown() {
388        let error = EncodeError::from(NonZeroI32::new(99).expect("99 is non-zero"));
389
390        assert_eq!(error, EncodeError::Unknown(99));
391        assert_eq!(error.to_string(), "Encode Error 99: unknown");
392    }
393}