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::batch_add_error::BatchAddError;
8use crate::mtmd::MtmdEvalError;
9use crate::mtmd::mtmd_input_chunk_type::MtmdInputChunkTypeError;
10
11pub type Result<TValue> = std::result::Result<TValue, LlamaCppError>;
13
14#[derive(Debug, Eq, PartialEq, thiserror::Error)]
16pub enum LlamaCppError {
17 #[error("BackendAlreadyInitialized")]
20 BackendAlreadyInitialized,
21 #[error("{0}")]
23 ChatTemplateError(#[from] ChatTemplateError),
24 #[error("{0}")]
26 DecodeError(#[from] DecodeError),
27 #[error("{0}")]
29 EncodeError(#[from] EncodeError),
30 #[error("{0}")]
32 LlamaModelLoadError(#[from] LlamaModelLoadError),
33 #[error("{0}")]
35 LlamaContextLoadError(#[from] LlamaContextLoadError),
36 #[error["{0}"]]
38 BatchAddError(#[from] BatchAddError),
39 #[error(transparent)]
41 EmbeddingError(#[from] EmbeddingsError),
42 #[error("Backend device {0} not found")]
44 BackendDeviceNotFound(usize),
45 #[error("Max devices exceeded. Max devices is {0}")]
47 MaxDevicesExceeded(usize),
48 #[error("JsonSchemaToGrammarError: {0}")]
50 JsonSchemaToGrammarError(String),
51 #[error(transparent)]
53 FitError(#[from] FitError),
54}
55
56#[derive(Debug, Eq, PartialEq, thiserror::Error)]
58pub enum ChatTemplateError {
59 #[error("chat template not found - returned null pointer")]
61 MissingTemplate,
62
63 #[error("null byte in string {0}")]
65 NullError(#[from] NulError),
66
67 #[error(transparent)]
69 Utf8Error(#[from] std::str::Utf8Error),
70}
71
72#[derive(Debug, Eq, PartialEq, thiserror::Error)]
74pub enum MetaValError {
75 #[error("null byte in string {0}")]
77 NullError(#[from] NulError),
78
79 #[error("FromUtf8Error {0}")]
81 FromUtf8Error(#[from] FromUtf8Error),
82
83 #[error("Negative return value. Likely due to a missing index or key. Got return value: {0}")]
85 NegativeReturn(i32),
86}
87
88#[derive(Debug, Eq, PartialEq, thiserror::Error)]
90pub enum LlamaContextLoadError {
91 #[error("null reference from llama.cpp")]
93 NullReturn,
94}
95
96#[derive(Debug, Eq, PartialEq, thiserror::Error)]
98pub enum DecodeError {
99 #[error("Decode Error 1: NoKvCacheSlot")]
101 NoKvCacheSlot,
102 #[error("Decode Error 2: Aborted")]
104 Aborted,
105 #[error("Decode Error -1: n_tokens == 0")]
107 NTokensZero,
108 #[error("Decode Error {0}: unknown")]
110 Unknown(c_int),
111}
112
113#[derive(Debug, Eq, PartialEq, thiserror::Error)]
115pub enum EncodeError {
116 #[error("Encode Error 1: NoKvCacheSlot")]
118 NoKvCacheSlot,
119 #[error("Encode Error -1: n_tokens == 0")]
121 NTokensZero,
122 #[error("Encode Error {0}: unknown")]
124 Unknown(c_int),
125}
126
127#[derive(Debug, Eq, PartialEq, thiserror::Error)]
129pub enum EmbeddingsError {
130 #[error("Embeddings weren't enabled in the context options")]
132 NotEnabled,
133 #[error("Logits were not enabled for the given token")]
135 LogitsNotEnabled,
136 #[error("Can't use sequence embeddings with a model supporting only LLAMA_POOLING_TYPE_NONE")]
138 NonePoolType,
139 #[error("Invalid embedding dimension: {0}")]
141 InvalidEmbeddingDimension(#[source] std::num::TryFromIntError),
142}
143
144#[derive(Debug, Eq, PartialEq, thiserror::Error)]
146pub enum LogitsError {
147 #[error("logits data pointer is null")]
149 NullLogits,
150 #[error("logit for token index {0} is not initialized")]
152 TokenNotInitialized(i32),
153 #[error("token index {token_index} exceeds context size {context_size}")]
155 TokenIndexExceedsContext {
156 token_index: u32,
158 context_size: u32,
160 },
161 #[error("n_vocab does not fit into usize: {0}")]
163 VocabSizeOverflow(#[source] std::num::TryFromIntError),
164 #[error("token_index does not fit into u32: {0}")]
166 TokenIndexOverflow(#[source] std::num::TryFromIntError),
167}
168
169#[derive(Debug, Eq, PartialEq, thiserror::Error)]
171pub enum GrammarError {
172 #[error("Grammar root not found in grammar string")]
174 RootNotFound,
175 #[error("Trigger word contains null bytes: {0}")]
177 TriggerWordNullBytes(NulError),
178 #[error("Grammar string or root contains null bytes: {0}")]
180 GrammarNullBytes(NulError),
181 #[error("String contains null bytes: {0}")]
183 NulError(#[from] NulError),
184 #[error("Grammar initialization failed: {0}")]
186 NullGrammar(String),
187 #[error("Integer overflow: {0}")]
189 IntegerOverflow(String),
190 #[error("llguidance error: {0}")]
192 LlguidanceError(String),
193}
194
195#[derive(Debug, Eq, PartialEq, thiserror::Error)]
197pub enum SamplingError {
198 #[error("Integer overflow: {0}")]
200 IntegerOverflow(String),
201}
202
203#[derive(Debug, Eq, PartialEq, thiserror::Error)]
205pub enum SampleError {
206 #[error("C++ exception during sampling: {0}")]
208 CppException(String),
209
210 #[error("Invalid argument passed to sampler")]
212 InvalidArgument,
213}
214
215impl From<NonZeroI32> for DecodeError {
217 fn from(value: NonZeroI32) -> Self {
218 match value.get() {
219 1 => Self::NoKvCacheSlot,
220 2 => Self::Aborted,
221 -1 => Self::NTokensZero,
222 error_code => Self::Unknown(error_code),
223 }
224 }
225}
226
227impl From<NonZeroI32> for EncodeError {
229 fn from(value: NonZeroI32) -> Self {
230 match value.get() {
231 1 => Self::NoKvCacheSlot,
232 -1 => Self::NTokensZero,
233 error_code => Self::Unknown(error_code),
234 }
235 }
236}
237
238#[derive(Debug, Eq, PartialEq, thiserror::Error)]
240pub enum LlamaModelLoadError {
241 #[error("null byte in string {0}")]
243 NullError(#[from] NulError),
244 #[error("null result from llama cpp")]
246 NullResult,
247 #[error("failed to convert path {0} to str")]
249 PathToStrError(PathBuf),
250 #[error("model file not found: {0}")]
252 FileNotFound(PathBuf),
253}
254
255#[derive(Debug, Eq, PartialEq, thiserror::Error)]
257pub enum LlamaLoraAdapterInitError {
258 #[error("null byte in string {0}")]
260 NullError(#[from] NulError),
261 #[error("null result from llama cpp")]
263 NullResult,
264 #[error("failed to convert path {0} to str")]
266 PathToStrError(PathBuf),
267 #[error("adapter file not found: {0}")]
269 FileNotFound(PathBuf),
270}
271
272#[derive(Debug, Eq, PartialEq, thiserror::Error)]
274pub enum LlamaLoraAdapterSetError {
275 #[error("error code from llama cpp")]
277 ErrorResult(i32),
278}
279
280#[derive(Debug, Eq, PartialEq, thiserror::Error)]
282pub enum LlamaLoraAdapterRemoveError {
283 #[error("error code from llama cpp")]
285 ErrorResult(i32),
286}
287
288#[derive(Debug, thiserror::Error, Clone)]
290#[non_exhaustive]
291pub enum TokenToStringError {
292 #[error("Unknown Token Type")]
294 UnknownTokenType,
295 #[error("Insufficient Buffer Space {0}")]
297 InsufficientBufferSpace(c_int),
298 #[error("FromUtf8Error {0}")]
300 FromUtf8Error(#[from] FromUtf8Error),
301 #[error("Integer conversion error: {0}")]
303 IntConversionError(#[from] std::num::TryFromIntError),
304}
305
306#[derive(Debug, thiserror::Error)]
308pub enum StringToTokenError {
309 #[error("{0}")]
311 NulError(#[from] NulError),
312 #[error("{0}")]
313 CIntConversionError(#[from] std::num::TryFromIntError),
315}
316
317#[derive(Debug, thiserror::Error)]
319pub enum NewLlamaChatMessageError {
320 #[error("{0}")]
322 NulError(#[from] NulError),
323}
324
325#[derive(Debug, thiserror::Error)]
327pub enum ApplyChatTemplateError {
328 #[error("{0}")]
330 FromUtf8Error(#[from] FromUtf8Error),
331 #[error("Integer conversion error: {0}")]
333 IntConversionError(#[from] std::num::TryFromIntError),
334}
335
336#[derive(Debug, thiserror::Error)]
338pub enum MarkerDetectionError {
339 #[error("ffi error {0}")]
341 FfiError(i32),
342 #[error("c++ exception during template analysis: {0}")]
344 AnalyzeException(String),
345 #[error("ffi returned non-utf8 marker bytes: {0}")]
347 MarkerUtf8Error(#[from] FromUtf8Error),
348}
349
350#[derive(Debug, thiserror::Error)]
352pub enum ParseChatMessageError {
353 #[error("ffi error {0}")]
355 FfiError(i32),
356 #[error("c++ exception during chat parse: {0}")]
358 ParseException(String),
359 #[error("ffi returned non-utf8 string: {0}")]
361 StringUtf8Error(#[from] FromUtf8Error),
362 #[error("tools_json is not valid JSON: {0}")]
364 ToolsJsonInvalid(#[source] serde_json::Error),
365 #[error("tools_json must be a JSON array")]
367 ToolsJsonNotArray,
368 #[error("could not serialize tools to JSON: {0}")]
370 ToolsSerialization(String),
371 #[error("model has no chat template")]
373 NoChatTemplate,
374 #[error("template-override fallback parser failed: {0}")]
376 TemplateOverrideFailed(#[from] ToolCallFormatFailure),
377}
378
379#[derive(Debug, thiserror::Error)]
381pub enum ToolCallFormatFailure {
382 #[error("bracketed-args fallback parser: {0}")]
383 BracketedArgs(#[from] BracketedArgsFailure),
384 #[error("json-object fallback parser: {0}")]
385 JsonObject(#[from] JsonObjectFailure),
386 #[error("key-value-xml-tags fallback parser: {0}")]
387 KeyValueXmlTags(#[from] KeyValueXmlTagsFailure),
388 #[error("paired-quote fallback parser: {0}")]
389 PairedQuote(#[from] PairedQuoteFailure),
390 #[error("xml-function-tags fallback parser: {0}")]
391 XmlFunctionTags(#[from] XmlFunctionTagsFailure),
392}
393
394#[derive(Debug, thiserror::Error)]
396pub enum JsonObjectFailure {
397 #[error("tool call body has malformed JSON: {message}")]
398 InvalidJson { message: String },
399}
400
401#[derive(Debug, thiserror::Error)]
403pub enum BracketedArgsFailure {
404 #[error("tool call '{tool_name}' arguments are not valid JSON: {message}")]
405 InvalidJsonArguments { tool_name: String, message: String },
406 #[error("tool call '{tool_name}' arguments truncated before JSON value completed")]
407 UnterminatedArguments { tool_name: String },
408}
409
410#[derive(Debug, thiserror::Error)]
412pub enum PairedQuoteFailure {
413 #[error("empty key in tool call '{tool_name}' arguments")]
414 EmptyKey { tool_name: String },
415 #[error("tool call '{tool_name}' translated arguments are not valid JSON: {message}")]
416 InvalidJsonArguments { tool_name: String, message: String },
417 #[error("tool call '{tool_name}' has unclosed quoted value for key '{key}'")]
418 UnclosedQuotedValue { tool_name: String, key: String },
419 #[error("tool call '{tool_name}' arguments ended without close marker (state: {state})")]
420 UnclosedArgumentBlock {
421 tool_name: String,
422 state: &'static str,
423 },
424 #[error(
425 "tool call '{tool_name}' has unexpected character '{character}' after value for key '{key}'"
426 )]
427 UnexpectedCharAfterValue {
428 tool_name: String,
429 key: String,
430 character: char,
431 },
432}
433
434#[derive(Debug, thiserror::Error)]
436pub enum KeyValueXmlTagsFailure {
437 #[error("tool call function tag has empty name")]
438 EmptyFunctionName,
439 #[error("tool call function block is missing close tag '{expected_close}'")]
440 UnclosedFunctionBlock { expected_close: String },
441 #[error("tool call function '{function_name}' has key tag with empty content")]
442 EmptyKey { function_name: String },
443 #[error("tool call function '{function_name}' is missing key close tag '{expected_close}'")]
444 UnclosedKeyTag {
445 function_name: String,
446 expected_close: String,
447 },
448 #[error(
449 "tool call function '{function_name}' key '{key}' is missing value open tag '{expected_open}'"
450 )]
451 MissingValueTag {
452 function_name: String,
453 key: String,
454 expected_open: String,
455 },
456 #[error(
457 "tool call function '{function_name}' key '{key}' is missing value close tag '{expected_close}'"
458 )]
459 UnclosedValueTag {
460 function_name: String,
461 key: String,
462 expected_close: String,
463 },
464}
465
466#[derive(Debug, thiserror::Error)]
468pub enum XmlFunctionTagsFailure {
469 #[error("tool call function tag has empty name")]
470 EmptyFunctionName,
471 #[error("tool call function '{function_name}' is missing close tag '{expected_close}'")]
472 UnclosedFunctionBlock {
473 function_name: String,
474 expected_close: String,
475 },
476 #[error("tool call function '{function_name}' has parameter with empty name")]
477 EmptyParameterName { function_name: String },
478 #[error(
479 "tool call function '{function_name}' parameter '{parameter_name}' is missing close tag '{expected_close}'"
480 )]
481 UnclosedParameterBlock {
482 function_name: String,
483 parameter_name: String,
484 expected_close: String,
485 },
486}
487
488#[derive(Debug, thiserror::Error)]
490pub enum EvalMultimodalChunksError {
491 #[error("{0}")]
493 EvalFailed(#[from] MtmdEvalError),
494 #[error("{0}")]
496 UnknownChunkType(#[from] MtmdInputChunkTypeError),
497 #[error("chunk index {0} out of bounds during post-eval walk")]
499 ChunkOutOfBounds(usize),
500}
501
502#[derive(Debug, thiserror::Error)]
504pub enum SamplerAcceptError {
505 #[error("C++ exception during sampler accept: {0}")]
507 CppException(String),
508
509 #[error("Invalid argument passed to sampler accept")]
511 InvalidArgument,
512}
513
514#[derive(Debug, Eq, PartialEq, thiserror::Error)]
516pub enum ModelParamsError {
517 #[error("No available slot in override vector")]
519 NoAvailableSlot,
520 #[error("Override slot is not empty")]
522 SlotNotEmpty,
523 #[error("Invalid character in key: byte {byte}, {reason}")]
525 InvalidCharacterInKey {
526 byte: u8,
528 reason: String,
530 },
531}
532
533#[derive(Debug, Eq, PartialEq, thiserror::Error)]
535pub enum TokenSamplingError {
536 #[error("No token was selected by the sampler")]
538 NoTokenSelected,
539}
540
541#[derive(Debug, Clone, Copy, Eq, PartialEq, thiserror::Error)]
543pub enum FitError {
544 #[error("could not find allocations that fit available memory")]
546 Failure,
547 #[error("hard error during parameter fitting")]
550 Error,
551}
552
553#[cfg(test)]
554mod tests {
555 use std::num::NonZeroI32;
556
557 use super::{DecodeError, EncodeError};
558
559 #[test]
560 fn decode_error_no_kv_cache_slot() {
561 let error = DecodeError::from(NonZeroI32::new(1).expect("1 is non-zero"));
562
563 assert_eq!(error, DecodeError::NoKvCacheSlot);
564 assert_eq!(error.to_string(), "Decode Error 1: NoKvCacheSlot");
565 }
566
567 #[test]
568 fn decode_error_n_tokens_zero() {
569 let error = DecodeError::from(NonZeroI32::new(-1).expect("-1 is non-zero"));
570
571 assert_eq!(error, DecodeError::NTokensZero);
572 assert_eq!(error.to_string(), "Decode Error -1: n_tokens == 0");
573 }
574
575 #[test]
576 fn decode_error_aborted() {
577 let error = DecodeError::from(NonZeroI32::new(2).expect("2 is non-zero"));
578
579 assert_eq!(error, DecodeError::Aborted);
580 assert_eq!(error.to_string(), "Decode Error 2: Aborted");
581 }
582
583 #[test]
584 fn decode_error_unknown() {
585 let error = DecodeError::from(NonZeroI32::new(42).expect("42 is non-zero"));
586
587 assert_eq!(error, DecodeError::Unknown(42));
588 assert_eq!(error.to_string(), "Decode Error 42: unknown");
589 }
590
591 #[test]
592 fn encode_error_no_kv_cache_slot() {
593 let error = EncodeError::from(NonZeroI32::new(1).expect("1 is non-zero"));
594
595 assert_eq!(error, EncodeError::NoKvCacheSlot);
596 assert_eq!(error.to_string(), "Encode Error 1: NoKvCacheSlot");
597 }
598
599 #[test]
600 fn encode_error_n_tokens_zero() {
601 let error = EncodeError::from(NonZeroI32::new(-1).expect("-1 is non-zero"));
602
603 assert_eq!(error, EncodeError::NTokensZero);
604 assert_eq!(error.to_string(), "Encode Error -1: n_tokens == 0");
605 }
606
607 #[test]
608 fn encode_error_unknown() {
609 let error = EncodeError::from(NonZeroI32::new(99).expect("99 is non-zero"));
610
611 assert_eq!(error, EncodeError::Unknown(99));
612 assert_eq!(error.to_string(), "Encode Error 99: unknown");
613 }
614}