use thiserror::Error;
#[derive(Debug, Error)]
pub enum EmbedError {
#[error("Failed to initialize embedding model: {0}")]
ModelInit(String),
#[error("Model not found: {0}")]
ModelNotFound(String),
#[error("Embedding failed: {0}")]
Embedding(String),
#[error("Dimension mismatch: expected {expected}, got {actual}")]
DimensionMismatch { expected: usize, actual: usize },
#[error("Index serialization error: {0}")]
Serialization(String),
#[error("IO error: {0}")]
Io(#[from] std::io::Error),
#[error("API error: {status} - {message}")]
Api { status: u16, message: String },
#[error("Rate limit exceeded, retry after {retry_after_secs} seconds")]
RateLimit { retry_after_secs: u64 },
#[error("Invalid API key")]
InvalidApiKey,
#[error("Cannot embed empty text")]
EmptyInput,
#[error("Batch size {size} exceeds maximum {max}")]
BatchTooLarge { size: usize, max: usize },
}
impl EmbedError {
pub fn is_retryable(&self) -> bool {
match self {
Self::RateLimit { .. } => true,
Self::Api { status, .. } if *status >= 500 => true,
_ => false,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_error_display() {
let err = EmbedError::DimensionMismatch {
expected: 1024,
actual: 384,
};
assert!(err.to_string().contains("1024"));
assert!(err.to_string().contains("384"));
}
#[test]
fn test_retryable() {
assert!(EmbedError::RateLimit { retry_after_secs: 60 }.is_retryable());
assert!(EmbedError::Api {
status: 500,
message: "Server error".into()
}
.is_retryable());
assert!(!EmbedError::InvalidApiKey.is_retryable());
assert!(!EmbedError::Api {
status: 400,
message: "Bad request".into()
}
.is_retryable());
}
}