langextract_rust/
exceptions.rs1use thiserror::Error;
7
8pub type LangExtractResult<T> = Result<T, LangExtractError>;
10
11#[derive(Error, Debug)]
16pub enum LangExtractError {
17 #[error("Configuration error: {0}")]
19 ConfigurationError(String),
20
21 #[error("Inference error: {message}")]
23 InferenceError {
24 message: String,
25 provider: Option<String>,
26 #[source]
27 source: Option<Box<dyn std::error::Error + Send + Sync>>,
28 },
29
30 #[error("Invalid input: {0}")]
32 InvalidInput(String),
33
34 #[error("Network error: {0}")]
36 NetworkError(#[from] reqwest::Error),
37
38 #[error("Parsing error: {0}")]
40 ParsingError(String),
41
42 #[error("I/O error: {0}")]
44 IoError(#[from] std::io::Error),
45
46 #[error("Serialization error: {0}")]
48 SerializationError(String),
49
50 #[error("Tokenization error: {0}")]
52 TokenizationError(String),
53
54 #[error("Chunking error: {0}")]
56 ChunkingError(String),
57
58 #[error("Visualization error: {0}")]
60 VisualizationError(String),
61
62 #[error("Unexpected error: {0}")]
64 UnexpectedError(String),
65}
66
67impl LangExtractError {
68 pub fn configuration<S: Into<String>>(message: S) -> Self {
70 Self::ConfigurationError(message.into())
71 }
72
73 pub fn inference<S: Into<String>>(
75 message: S,
76 provider: Option<String>,
77 source: Option<Box<dyn std::error::Error + Send + Sync>>,
78 ) -> Self {
79 Self::InferenceError {
80 message: message.into(),
81 provider,
82 source,
83 }
84 }
85
86 pub fn inference_simple<S: Into<String>>(message: S) -> Self {
88 Self::InferenceError {
89 message: message.into(),
90 provider: None,
91 source: None,
92 }
93 }
94
95 pub fn invalid_input<S: Into<String>>(message: S) -> Self {
97 Self::InvalidInput(message.into())
98 }
99
100 pub fn parsing<S: Into<String>>(message: S) -> Self {
102 Self::ParsingError(message.into())
103 }
104
105 pub fn serialization<S: Into<String>>(message: S) -> Self {
107 Self::SerializationError(message.into())
108 }
109
110 pub fn tokenization<S: Into<String>>(message: S) -> Self {
112 Self::TokenizationError(message.into())
113 }
114
115 pub fn chunking<S: Into<String>>(message: S) -> Self {
117 Self::ChunkingError(message.into())
118 }
119
120 pub fn visualization<S: Into<String>>(message: S) -> Self {
122 Self::VisualizationError(message.into())
123 }
124
125 pub fn unexpected<S: Into<String>>(message: S) -> Self {
127 Self::UnexpectedError(message.into())
128 }
129
130 pub fn provider(&self) -> Option<&str> {
132 match self {
133 Self::InferenceError { provider, .. } => provider.as_deref(),
134 _ => None,
135 }
136 }
137
138 pub fn is_configuration_error(&self) -> bool {
140 matches!(self, Self::ConfigurationError(_))
141 }
142
143 pub fn is_inference_error(&self) -> bool {
145 matches!(self, Self::InferenceError { .. })
146 }
147
148 pub fn is_network_error(&self) -> bool {
150 matches!(self, Self::NetworkError(_))
151 }
152
153 pub fn is_parsing_error(&self) -> bool {
155 matches!(self, Self::ParsingError(_))
156 }
157}
158
159impl From<serde_json::Error> for LangExtractError {
161 fn from(err: serde_json::Error) -> Self {
162 Self::SerializationError(format!("JSON error: {}", err))
163 }
164}
165
166impl From<serde_yaml::Error> for LangExtractError {
168 fn from(err: serde_yaml::Error) -> Self {
169 Self::SerializationError(format!("YAML error: {}", err))
170 }
171}
172
173impl From<dotenvy::Error> for LangExtractError {
175 fn from(err: dotenvy::Error) -> Self {
176 Self::ConfigurationError(format!("Environment variable error: {}", err))
177 }
178}
179
180#[derive(Error, Debug)]
182pub enum InferenceError {
183 #[error("No outputs available: {message}")]
185 NoOutputsAvailable { message: String },
186
187 #[error("Rate limit exceeded for provider {provider}")]
189 RateLimitExceeded { provider: String },
190
191 #[error("Invalid model configuration: {message}")]
193 InvalidConfiguration { message: String },
194
195 #[error("Model not found: {model_id}")]
197 ModelNotFound { model_id: String },
198
199 #[error("Authentication failed for provider {provider}: {message}")]
201 AuthenticationFailed { provider: String, message: String },
202
203 #[error("Quota exceeded for provider {provider}")]
205 QuotaExceeded { provider: String },
206
207 #[error("Service unavailable for provider {provider}")]
209 ServiceUnavailable { provider: String },
210
211 #[error("Inference failed: {message}")]
213 InferenceFailed { message: String },
214}
215
216impl From<InferenceError> for LangExtractError {
217 fn from(err: InferenceError) -> Self {
218 let provider = match &err {
219 InferenceError::RateLimitExceeded { provider } => Some(provider.clone()),
220 InferenceError::AuthenticationFailed { provider, .. } => Some(provider.clone()),
221 InferenceError::QuotaExceeded { provider } => Some(provider.clone()),
222 InferenceError::ServiceUnavailable { provider } => Some(provider.clone()),
223 _ => None,
224 };
225
226 Self::InferenceError {
227 message: err.to_string(),
228 provider,
229 source: Some(Box::new(err)),
230 }
231 }
232}
233
234#[derive(Error, Debug)]
236pub enum ResolverError {
237 #[error("Failed to parse output: {message}")]
239 ParseError { message: String },
240
241 #[error("Invalid output format: expected {expected}, got {actual}")]
243 InvalidFormat { expected: String, actual: String },
244
245 #[error("Missing required fields: {fields:?}")]
247 MissingFields { fields: Vec<String> },
248
249 #[error("Schema validation failed: {message}")]
251 SchemaValidationFailed { message: String },
252}
253
254impl From<ResolverError> for LangExtractError {
255 fn from(err: ResolverError) -> Self {
256 Self::ParsingError(err.to_string())
257 }
258}
259
260#[cfg(test)]
261mod tests {
262 use super::*;
263
264 #[test]
265 fn test_error_creation() {
266 let config_err = LangExtractError::configuration("Missing API key");
267 assert!(config_err.is_configuration_error());
268 assert!(!config_err.is_inference_error());
269
270 let inference_err = LangExtractError::inference(
271 "Model failed",
272 Some("gemini".to_string()),
273 None,
274 );
275 assert!(inference_err.is_inference_error());
276 assert_eq!(inference_err.provider(), Some("gemini"));
277
278 let parsing_err = LangExtractError::parsing("Invalid JSON");
279 assert!(parsing_err.is_parsing_error());
280 }
281
282 #[test]
283 fn test_error_conversion() {
284 let json_error = serde_json::from_str::<serde_json::Value>("invalid json");
285 assert!(json_error.is_err());
286
287 let lang_error: LangExtractError = json_error.unwrap_err().into();
288 assert!(lang_error.is_parsing_error() || matches!(lang_error, LangExtractError::SerializationError(_)));
289 }
290
291 #[test]
292 fn test_inference_error_conversion() {
293 let inference_err = InferenceError::ModelNotFound {
294 model_id: "unknown-model".to_string(),
295 };
296
297 let lang_err: LangExtractError = inference_err.into();
298 assert!(lang_err.is_inference_error());
299 }
300
301 #[test]
302 fn test_error_display() {
303 let error = LangExtractError::configuration("Test error message");
304 let display = format!("{}", error);
305 assert!(display.contains("Configuration error"));
306 assert!(display.contains("Test error message"));
307 }
308
309 #[test]
310 fn test_resolver_error_conversion() {
311 let resolver_err = ResolverError::ParseError {
312 message: "Invalid JSON structure".to_string(),
313 };
314
315 let lang_err: LangExtractError = resolver_err.into();
316 assert!(lang_err.is_parsing_error());
317 }
318}