1use thiserror::Error;
4
5#[derive(Debug, Error)]
7pub enum EmbedError {
8 #[error("Failed to initialize embedding model: {0}")]
10 ModelInit(String),
11
12 #[error("Model not found: {0}")]
14 ModelNotFound(String),
15
16 #[error("Embedding failed: {0}")]
18 Embedding(String),
19
20 #[error("Dimension mismatch: expected {expected}, got {actual}")]
22 DimensionMismatch { expected: usize, actual: usize },
23
24 #[error("Index serialization error: {0}")]
26 Serialization(String),
27
28 #[error("IO error: {0}")]
30 Io(#[from] std::io::Error),
31
32 #[error("API error: {status} - {message}")]
34 Api { status: u16, message: String },
35
36 #[error("Rate limit exceeded, retry after {retry_after_secs} seconds")]
38 RateLimit { retry_after_secs: u64 },
39
40 #[error("Invalid API key")]
42 InvalidApiKey,
43
44 #[error("Cannot embed empty text")]
46 EmptyInput,
47
48 #[error("Batch size {size} exceeds maximum {max}")]
50 BatchTooLarge { size: usize, max: usize },
51}
52
53impl EmbedError {
54 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}