Skip to main content

skm_embed/
error.rs

1//! Error types for skm-embed.
2
3use thiserror::Error;
4
5/// Errors from embedding operations.
6#[derive(Debug, Error)]
7pub enum EmbedError {
8    /// Model initialization failed.
9    #[error("Failed to initialize embedding model: {0}")]
10    ModelInit(String),
11
12    /// Model not found or could not be loaded.
13    #[error("Model not found: {0}")]
14    ModelNotFound(String),
15
16    /// Embedding computation failed.
17    #[error("Embedding failed: {0}")]
18    Embedding(String),
19
20    /// Dimension mismatch between embeddings.
21    #[error("Dimension mismatch: expected {expected}, got {actual}")]
22    DimensionMismatch { expected: usize, actual: usize },
23
24    /// Index serialization/deserialization failed.
25    #[error("Index serialization error: {0}")]
26    Serialization(String),
27
28    /// IO error.
29    #[error("IO error: {0}")]
30    Io(#[from] std::io::Error),
31
32    /// API error (for remote providers).
33    #[error("API error: {status} - {message}")]
34    Api { status: u16, message: String },
35
36    /// Rate limit exceeded.
37    #[error("Rate limit exceeded, retry after {retry_after_secs} seconds")]
38    RateLimit { retry_after_secs: u64 },
39
40    /// Invalid API key.
41    #[error("Invalid API key")]
42    InvalidApiKey,
43
44    /// Empty input.
45    #[error("Cannot embed empty text")]
46    EmptyInput,
47
48    /// Batch too large.
49    #[error("Batch size {size} exceeds maximum {max}")]
50    BatchTooLarge { size: usize, max: usize },
51}
52
53impl EmbedError {
54    /// Check if this is a retryable error.
55    pub fn is_retryable(&self) -> bool {
56        match self {
57            Self::RateLimit { .. } => true,
58            Self::Api { status, .. } if *status >= 500 => true,
59            _ => false,
60        }
61    }
62}
63
64#[cfg(test)]
65mod tests {
66    use super::*;
67
68    #[test]
69    fn test_error_display() {
70        let err = EmbedError::DimensionMismatch {
71            expected: 1024,
72            actual: 384,
73        };
74        assert!(err.to_string().contains("1024"));
75        assert!(err.to_string().contains("384"));
76    }
77
78    #[test]
79    fn test_retryable() {
80        assert!(EmbedError::RateLimit { retry_after_secs: 60 }.is_retryable());
81        assert!(EmbedError::Api {
82            status: 500,
83            message: "Server error".into()
84        }
85        .is_retryable());
86        assert!(!EmbedError::InvalidApiKey.is_retryable());
87        assert!(!EmbedError::Api {
88            status: 400,
89            message: "Bad request".into()
90        }
91        .is_retryable());
92    }
93}