1use thiserror::Error;
4
5pub type BonsaiResult<T> = Result<T, BonsaiError>;
7
8#[derive(Error, Debug)]
10pub enum BonsaiError {
11 #[error("invalid GGUF magic number: expected 0x46554747, got 0x{magic:08X}")]
13 InvalidMagic { magic: u32 },
14
15 #[error("unsupported GGUF version: {version} (supported: 2, 3)")]
17 UnsupportedVersion { version: u32 },
18
19 #[error("invalid metadata for key '{key}': {reason}")]
21 InvalidMetadata { key: String, reason: String },
22
23 #[error("tensor not found: '{name}'")]
25 TensorNotFound { name: String },
26
27 #[error("unsupported quantization type id {type_id}: known execution types are Q1_0_g128=41, TQ2_0_g128=42, TQ2_0=35")]
29 UnsupportedQuantType { type_id: u32 },
30
31 #[error("memory mapping failed: {0}")]
33 MmapError(#[from] std::io::Error),
34
35 #[error("unexpected end of file at offset {offset}")]
37 UnexpectedEof { offset: u64 },
38
39 #[error("alignment error: expected {expected}-byte alignment at offset {offset}")]
41 AlignmentError { expected: usize, offset: u64 },
42
43 #[error("invalid UTF-8 string at offset {offset}")]
45 InvalidString { offset: u64 },
46
47 #[error("missing config key '{key}' in model metadata")]
49 MissingConfigKey { key: String },
50
51 #[error("tensor '{name}' shape mismatch: expected {expected:?}, got {actual:?}")]
53 ShapeMismatch {
54 name: String,
55 expected: Vec<u64>,
56 actual: Vec<u64>,
57 },
58
59 #[error("invalid Q1_0_g128 block: expected 18 bytes, got {actual}")]
61 InvalidBlockSize { actual: usize },
62
63 #[error("k-quant error: {reason}")]
65 KQuantError { reason: String },
66}
67
68impl BonsaiError {
69 pub fn error_code(&self) -> &str {
71 match self {
72 Self::InvalidMagic { .. } => "INVALID_MAGIC",
73 Self::UnsupportedVersion { .. } => "UNSUPPORTED_VERSION",
74 Self::InvalidMetadata { .. } => "INVALID_METADATA",
75 Self::TensorNotFound { .. } => "TENSOR_NOT_FOUND",
76 Self::UnsupportedQuantType { .. } => "UNSUPPORTED_QUANT_TYPE",
77 Self::MmapError(_) => "MMAP_ERROR",
78 Self::UnexpectedEof { .. } => "UNEXPECTED_EOF",
79 Self::AlignmentError { .. } => "ALIGNMENT_ERROR",
80 Self::InvalidString { .. } => "INVALID_STRING",
81 Self::MissingConfigKey { .. } => "MISSING_CONFIG_KEY",
82 Self::ShapeMismatch { .. } => "SHAPE_MISMATCH",
83 Self::InvalidBlockSize { .. } => "INVALID_BLOCK_SIZE",
84 Self::KQuantError { .. } => "K_QUANT_ERROR",
85 }
86 }
87
88 pub fn is_retryable(&self) -> bool {
90 matches!(self, Self::MmapError(_))
91 }
92}