1use std::fmt;
7
8#[derive(Debug)]
10pub enum GraphRAGError {
11 Config {
13 message: String
15 },
16
17 NotInitialized,
19
20 NoDocuments,
22
23 Io(std::io::Error),
25
26 #[cfg(feature = "ureq")]
28 Http(Box<ureq::Error>),
29
30 #[cfg(not(feature = "ureq"))]
32 Http(String),
33
34 Json(json::Error),
36
37 SerdeJson(serde_json::Error),
39
40 TextProcessing {
42 message: String
44 },
45
46 GraphConstruction {
48 message: String
50 },
51
52 VectorSearch {
54 message: String
56 },
57
58 EntityExtraction {
60 message: String
62 },
63
64 Retrieval {
66 message: String
68 },
69
70 Generation {
72 message: String
74 },
75
76 FunctionCall {
78 message: String
80 },
81
82 Storage {
84 message: String
86 },
87
88 Embedding {
90 message: String
92 },
93
94 LanguageModel {
96 message: String
98 },
99
100 Parallel {
102 message: String
104 },
105
106 Serialization {
108 message: String
110 },
111
112 Validation {
114 message: String
116 },
117
118 Network {
120 message: String
122 },
123
124 Auth {
126 message: String
128 },
129
130 NotFound {
132 resource: String,
134 id: String
136 },
137
138 AlreadyExists {
140 resource: String,
142 id: String
144 },
145
146 Timeout {
148 operation: String,
150 duration: std::time::Duration,
152 },
153
154 ResourceLimit {
156 resource: String,
158 limit: usize
160 },
161
162 DataCorruption {
164 message: String
166 },
167
168 Unsupported {
170 operation: String,
172 reason: String
174 },
175
176 RateLimit {
178 message: String
180 },
181
182 ConflictResolution {
184 message: String
186 },
187
188 IncrementalUpdate {
190 message: String
192 },
193}
194
195impl fmt::Display for GraphRAGError {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 match self {
198 GraphRAGError::Config { message } => {
199 write!(f, "Configuration error: {message}. \
200 Solution: Check your config file or use default settings with GraphRAG::builder()")
201 }
202 GraphRAGError::NotInitialized => {
203 write!(
204 f,
205 "GraphRAG not initialized. \
206 Solution: Call .initialize() or use .ask() which auto-initializes"
207 )
208 }
209 GraphRAGError::NoDocuments => {
210 write!(f, "No documents added. \
211 Solution: Use .add_document(), .add_document_from_text(), or .from_file() to add content")
212 }
213 GraphRAGError::Io(err) => {
214 write!(
215 f,
216 "I/O error: {err}. \
217 Solution: Check file permissions and that paths exist"
218 )
219 }
220 #[cfg(feature = "ureq")]
221 GraphRAGError::Http(err) => {
222 write!(
223 f,
224 "HTTP request error: {err}. \
225 Solution: Check network connectivity and service availability"
226 )
227 }
228 #[cfg(not(feature = "ureq"))]
229 GraphRAGError::Http(msg) => {
230 write!(
231 f,
232 "HTTP request error: {msg}. \
233 Solution: Check network connectivity and service availability"
234 )
235 }
236 GraphRAGError::Json(err) => {
237 write!(
238 f,
239 "JSON parsing error: {err}. \
240 Solution: Verify JSON format or use default configuration"
241 )
242 }
243 GraphRAGError::SerdeJson(err) => {
244 write!(
245 f,
246 "JSON serialization error: {err}. \
247 Solution: Verify data structure compatibility"
248 )
249 }
250 GraphRAGError::TextProcessing { message } => {
251 write!(
252 f,
253 "Text processing error: {message}. \
254 Solution: Check text content and chunk size configuration"
255 )
256 }
257 GraphRAGError::GraphConstruction { message } => {
258 write!(
259 f,
260 "Graph construction error: {message}. \
261 Solution: Initialize GraphRAG system and add documents first"
262 )
263 }
264 GraphRAGError::VectorSearch { message } => {
265 write!(f, "Vector search error: {message}. \
266 Solution: Ensure embeddings are initialized with .initialize_embeddings()")
267 }
268 GraphRAGError::EntityExtraction { message } => {
269 write!(f, "Entity extraction error: {message}. \
270 Solution: Check entity extraction configuration or use lower confidence threshold")
271 }
272 GraphRAGError::Retrieval { message } => {
273 write!(
274 f,
275 "Retrieval error: {message}. \
276 Solution: Ensure documents are added and graph is built"
277 )
278 }
279 GraphRAGError::Generation { message } => {
280 write!(f, "Answer generation error: {message}. \
281 Solution: Check LLM provider configuration or use GraphRAG::builder().auto_detect_llm()")
282 }
283 GraphRAGError::FunctionCall { message } => {
284 write!(f, "Function call error: {message}")
285 }
286 GraphRAGError::Storage { message } => {
287 write!(f, "Storage error: {message}")
288 }
289 GraphRAGError::Embedding { message } => {
290 write!(f, "Embedding error: {message}")
291 }
292 GraphRAGError::LanguageModel { message } => {
293 write!(f, "Language model error: {message}")
294 }
295 GraphRAGError::Parallel { message } => {
296 write!(f, "Parallel processing error: {message}")
297 }
298 GraphRAGError::Serialization { message } => {
299 write!(f, "Serialization error: {message}")
300 }
301 GraphRAGError::Validation { message } => {
302 write!(f, "Validation error: {message}")
303 }
304 GraphRAGError::Network { message } => {
305 write!(f, "Network error: {message}")
306 }
307 GraphRAGError::Auth { message } => {
308 write!(f, "Authentication error: {message}")
309 }
310 GraphRAGError::NotFound { resource, id } => {
311 write!(f, "{resource} not found: {id}")
312 }
313 GraphRAGError::AlreadyExists { resource, id } => {
314 write!(f, "{resource} already exists: {id}")
315 }
316 GraphRAGError::Timeout {
317 operation,
318 duration,
319 } => {
320 write!(f, "Operation '{operation}' timed out after {duration:?}")
321 }
322 GraphRAGError::ResourceLimit { resource, limit } => {
323 write!(f, "Resource limit exceeded for {resource}: {limit}")
324 }
325 GraphRAGError::DataCorruption { message } => {
326 write!(f, "Data corruption detected: {message}")
327 }
328 GraphRAGError::Unsupported { operation, reason } => {
329 write!(f, "Unsupported operation '{operation}': {reason}")
330 }
331 GraphRAGError::RateLimit { message } => {
332 write!(f, "Rate limit error: {message}")
333 }
334 GraphRAGError::ConflictResolution { message } => {
335 write!(f, "Conflict resolution error: {message}")
336 }
337 GraphRAGError::IncrementalUpdate { message } => {
338 write!(f, "Incremental update error: {message}")
339 }
340 }
341 }
342}
343
344impl std::error::Error for GraphRAGError {
345 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
346 match self {
347 GraphRAGError::Io(err) => Some(err),
348 #[cfg(feature = "ureq")]
349 GraphRAGError::Http(err) => Some(err.as_ref()),
350 #[cfg(not(feature = "ureq"))]
351 GraphRAGError::Http(_) => None,
352 GraphRAGError::Json(err) => Some(err),
353 GraphRAGError::SerdeJson(err) => Some(err),
354 _ => None,
355 }
356 }
357}
358
359impl From<std::io::Error> for GraphRAGError {
361 fn from(err: std::io::Error) -> Self {
362 GraphRAGError::Io(err)
363 }
364}
365
366#[cfg(feature = "ureq")]
367impl From<ureq::Error> for GraphRAGError {
368 fn from(err: ureq::Error) -> Self {
369 GraphRAGError::Http(Box::new(err))
370 }
371}
372
373impl From<json::Error> for GraphRAGError {
374 fn from(err: json::Error) -> Self {
375 GraphRAGError::Json(err)
376 }
377}
378
379impl From<serde_json::Error> for GraphRAGError {
380 fn from(err: serde_json::Error) -> Self {
381 GraphRAGError::SerdeJson(err)
382 }
383}
384
385#[cfg(feature = "rograg")]
387impl From<crate::rograg::logic_form::LogicFormError> for GraphRAGError {
388 fn from(err: crate::rograg::logic_form::LogicFormError) -> Self {
389 GraphRAGError::Retrieval {
390 message: format!("Logic form error: {err}"),
391 }
392 }
393}
394
395#[cfg(feature = "rograg")]
396impl From<crate::rograg::processor::ProcessingError> for GraphRAGError {
397 fn from(err: crate::rograg::processor::ProcessingError) -> Self {
398 GraphRAGError::Generation {
399 message: format!("Processing error: {err}"),
400 }
401 }
402}
403
404#[cfg(feature = "rograg")]
405impl From<crate::rograg::quality_metrics::MetricsError> for GraphRAGError {
406 fn from(err: crate::rograg::quality_metrics::MetricsError) -> Self {
407 GraphRAGError::Validation {
408 message: format!("Metrics error: {err}"),
409 }
410 }
411}
412
413#[cfg(feature = "rograg")]
414impl From<crate::rograg::streaming::StreamingError> for GraphRAGError {
415 fn from(err: crate::rograg::streaming::StreamingError) -> Self {
416 GraphRAGError::Generation {
417 message: format!("Streaming error: {err}"),
418 }
419 }
420}
421
422#[cfg(feature = "rograg")]
423impl From<crate::rograg::fuzzy_matcher::FuzzyMatchError> for GraphRAGError {
424 fn from(err: crate::rograg::fuzzy_matcher::FuzzyMatchError) -> Self {
425 GraphRAGError::Retrieval {
426 message: format!("Fuzzy match error: {err}"),
427 }
428 }
429}
430
431pub type Result<T> = std::result::Result<T, GraphRAGError>;
433
434pub trait ErrorContext<T> {
436 fn with_context(self, context: &str) -> Result<T>;
438
439 fn with_context_lazy<F>(self, f: F) -> Result<T>
441 where
442 F: FnOnce() -> String;
443}
444
445impl<T, E> ErrorContext<T> for std::result::Result<T, E>
446where
447 E: Into<GraphRAGError>,
448{
449 fn with_context(self, context: &str) -> Result<T> {
450 self.map_err(|e| {
451 let base_error = e.into();
452 match base_error {
453 GraphRAGError::Config { message } => GraphRAGError::Config {
454 message: format!("{context}: {message}"),
455 },
456 GraphRAGError::TextProcessing { message } => GraphRAGError::TextProcessing {
457 message: format!("{context}: {message}"),
458 },
459 GraphRAGError::GraphConstruction { message } => GraphRAGError::GraphConstruction {
460 message: format!("{context}: {message}"),
461 },
462 GraphRAGError::VectorSearch { message } => GraphRAGError::VectorSearch {
463 message: format!("{context}: {message}"),
464 },
465 GraphRAGError::EntityExtraction { message } => GraphRAGError::EntityExtraction {
466 message: format!("{context}: {message}"),
467 },
468 GraphRAGError::Retrieval { message } => GraphRAGError::Retrieval {
469 message: format!("{context}: {message}"),
470 },
471 GraphRAGError::Generation { message } => GraphRAGError::Generation {
472 message: format!("{context}: {message}"),
473 },
474 GraphRAGError::FunctionCall { message } => GraphRAGError::FunctionCall {
475 message: format!("{context}: {message}"),
476 },
477 GraphRAGError::Storage { message } => GraphRAGError::Storage {
478 message: format!("{context}: {message}"),
479 },
480 GraphRAGError::Embedding { message } => GraphRAGError::Embedding {
481 message: format!("{context}: {message}"),
482 },
483 GraphRAGError::LanguageModel { message } => GraphRAGError::LanguageModel {
484 message: format!("{context}: {message}"),
485 },
486 GraphRAGError::Parallel { message } => GraphRAGError::Parallel {
487 message: format!("{context}: {message}"),
488 },
489 GraphRAGError::Serialization { message } => GraphRAGError::Serialization {
490 message: format!("{context}: {message}"),
491 },
492 GraphRAGError::Validation { message } => GraphRAGError::Validation {
493 message: format!("{context}: {message}"),
494 },
495 GraphRAGError::Network { message } => GraphRAGError::Network {
496 message: format!("{context}: {message}"),
497 },
498 GraphRAGError::Auth { message } => GraphRAGError::Auth {
499 message: format!("{context}: {message}"),
500 },
501 GraphRAGError::DataCorruption { message } => GraphRAGError::DataCorruption {
502 message: format!("{context}: {message}"),
503 },
504 GraphRAGError::RateLimit { message } => GraphRAGError::RateLimit {
505 message: format!("{context}: {message}"),
506 },
507 GraphRAGError::ConflictResolution { message } => {
508 GraphRAGError::ConflictResolution {
509 message: format!("{context}: {message}"),
510 }
511 }
512 GraphRAGError::IncrementalUpdate { message } => GraphRAGError::IncrementalUpdate {
513 message: format!("{context}: {message}"),
514 },
515 other => other, }
517 })
518 }
519
520 fn with_context_lazy<F>(self, f: F) -> Result<T>
521 where
522 F: FnOnce() -> String,
523 {
524 match self {
525 Ok(value) => Ok(value),
526 Err(e) => {
527 let context = f();
528 Err(e).with_context(&context)
529 }
530 }
531 }
532}
533
534#[macro_export]
538macro_rules! config_error {
539 ($msg:expr) => {
540 $crate::GraphRAGError::Config {
541 message: $msg.to_string(),
542 }
543 };
544 ($fmt:expr, $($arg:tt)*) => {
545 $crate::GraphRAGError::Config {
546 message: format!($fmt, $($arg)*),
547 }
548 };
549}
550
551#[macro_export]
553macro_rules! storage_error {
554 ($msg:expr) => {
555 $crate::GraphRAGError::Storage {
556 message: $msg.to_string(),
557 }
558 };
559 ($fmt:expr, $($arg:tt)*) => {
560 $crate::GraphRAGError::Storage {
561 message: format!($fmt, $($arg)*),
562 }
563 };
564}
565
566#[macro_export]
568macro_rules! retrieval_error {
569 ($msg:expr) => {
570 $crate::GraphRAGError::Retrieval {
571 message: $msg.to_string(),
572 }
573 };
574 ($fmt:expr, $($arg:tt)*) => {
575 $crate::GraphRAGError::Retrieval {
576 message: format!($fmt, $($arg)*),
577 }
578 };
579}
580
581#[macro_export]
583macro_rules! generation_error {
584 ($msg:expr) => {
585 $crate::GraphRAGError::Generation {
586 message: $msg.to_string(),
587 }
588 };
589 ($fmt:expr, $($arg:tt)*) => {
590 $crate::GraphRAGError::Generation {
591 message: format!($fmt, $($arg)*),
592 }
593 };
594}
595
596#[derive(Debug, Clone, Copy, PartialEq, Eq)]
598pub enum ErrorSeverity {
599 Info,
601 Warning,
603 Error,
605 Critical,
607}
608
609impl GraphRAGError {
610 pub fn severity(&self) -> ErrorSeverity {
612 match self {
613 GraphRAGError::Config { .. } => ErrorSeverity::Critical,
614 GraphRAGError::NotInitialized => ErrorSeverity::Warning,
615 GraphRAGError::NoDocuments => ErrorSeverity::Warning,
616 GraphRAGError::Io(_) => ErrorSeverity::Error,
617 GraphRAGError::Http(_) => ErrorSeverity::Warning,
618 GraphRAGError::Json(_) | GraphRAGError::SerdeJson(_) => ErrorSeverity::Error,
619 GraphRAGError::TextProcessing { .. } => ErrorSeverity::Warning,
620 GraphRAGError::GraphConstruction { .. } => ErrorSeverity::Error,
621 GraphRAGError::VectorSearch { .. } => ErrorSeverity::Warning,
622 GraphRAGError::EntityExtraction { .. } => ErrorSeverity::Warning,
623 GraphRAGError::Retrieval { .. } => ErrorSeverity::Warning,
624 GraphRAGError::Generation { .. } => ErrorSeverity::Warning,
625 GraphRAGError::FunctionCall { .. } => ErrorSeverity::Warning,
626 GraphRAGError::Storage { .. } => ErrorSeverity::Error,
627 GraphRAGError::Embedding { .. } => ErrorSeverity::Warning,
628 GraphRAGError::LanguageModel { .. } => ErrorSeverity::Warning,
629 GraphRAGError::Parallel { .. } => ErrorSeverity::Error,
630 GraphRAGError::Serialization { .. } => ErrorSeverity::Error,
631 GraphRAGError::Validation { .. } => ErrorSeverity::Error,
632 GraphRAGError::Network { .. } => ErrorSeverity::Warning,
633 GraphRAGError::Auth { .. } => ErrorSeverity::Error,
634 GraphRAGError::NotFound { .. } => ErrorSeverity::Warning,
635 GraphRAGError::AlreadyExists { .. } => ErrorSeverity::Warning,
636 GraphRAGError::Timeout { .. } => ErrorSeverity::Warning,
637 GraphRAGError::ResourceLimit { .. } => ErrorSeverity::Error,
638 GraphRAGError::DataCorruption { .. } => ErrorSeverity::Critical,
639 GraphRAGError::Unsupported { .. } => ErrorSeverity::Error,
640 GraphRAGError::RateLimit { .. } => ErrorSeverity::Warning,
641 GraphRAGError::ConflictResolution { .. } => ErrorSeverity::Error,
642 GraphRAGError::IncrementalUpdate { .. } => ErrorSeverity::Error,
643 }
644 }
645
646 pub fn is_recoverable(&self) -> bool {
648 match self.severity() {
649 ErrorSeverity::Info | ErrorSeverity::Warning => true,
650 ErrorSeverity::Error => false,
651 ErrorSeverity::Critical => false,
652 }
653 }
654
655 pub fn category(&self) -> &'static str {
657 match self {
658 GraphRAGError::Config { .. } => "config",
659 GraphRAGError::NotInitialized => "initialization",
660 GraphRAGError::NoDocuments => "usage",
661 GraphRAGError::Io(_) => "io",
662 GraphRAGError::Http(_) => "http",
663 GraphRAGError::Json(_) | GraphRAGError::SerdeJson(_) => "serialization",
664 GraphRAGError::TextProcessing { .. } => "text_processing",
665 GraphRAGError::GraphConstruction { .. } => "graph",
666 GraphRAGError::VectorSearch { .. } => "vector_search",
667 GraphRAGError::EntityExtraction { .. } => "entity_extraction",
668 GraphRAGError::Retrieval { .. } => "retrieval",
669 GraphRAGError::Generation { .. } => "generation",
670 GraphRAGError::FunctionCall { .. } => "function_calling",
671 GraphRAGError::Storage { .. } => "storage",
672 GraphRAGError::Embedding { .. } => "embedding",
673 GraphRAGError::LanguageModel { .. } => "language_model",
674 GraphRAGError::Parallel { .. } => "parallel",
675 GraphRAGError::Serialization { .. } => "serialization",
676 GraphRAGError::Validation { .. } => "validation",
677 GraphRAGError::Network { .. } => "network",
678 GraphRAGError::Auth { .. } => "auth",
679 GraphRAGError::NotFound { .. } => "not_found",
680 GraphRAGError::AlreadyExists { .. } => "already_exists",
681 GraphRAGError::Timeout { .. } => "timeout",
682 GraphRAGError::ResourceLimit { .. } => "resource_limit",
683 GraphRAGError::DataCorruption { .. } => "data_corruption",
684 GraphRAGError::Unsupported { .. } => "unsupported",
685 GraphRAGError::RateLimit { .. } => "rate_limit",
686 GraphRAGError::ConflictResolution { .. } => "conflict_resolution",
687 GraphRAGError::IncrementalUpdate { .. } => "incremental_update",
688 }
689 }
690}
691
692impl From<regex::Error> for GraphRAGError {
693 fn from(err: regex::Error) -> Self {
694 GraphRAGError::Validation {
695 message: format!("Regex error: {err}"),
696 }
697 }
698}
699
700#[cfg(test)]
701mod tests {
702 use super::*;
703
704 #[test]
705 fn test_error_display() {
706 let error = GraphRAGError::Config {
707 message: "Invalid configuration".to_string(),
708 };
709 assert_eq!(
710 format!("{error}"),
711 "Configuration error: Invalid configuration. Solution: Check your config file or use default settings with GraphRAG::builder()"
712 );
713 }
714
715 #[test]
716 fn test_error_context() {
717 let result: std::result::Result<(), std::io::Error> = Err(std::io::Error::new(
718 std::io::ErrorKind::NotFound,
719 "file not found",
720 ));
721
722 let error = result.with_context("loading configuration").unwrap_err();
723 assert!(matches!(error, GraphRAGError::Io(_)));
724 }
725
726 #[test]
727 fn test_error_macros() {
728 let error = config_error!("test message");
729 assert!(matches!(error, GraphRAGError::Config { .. }));
730
731 let error = storage_error!("test {} {}", "formatted", "message");
732 assert!(matches!(error, GraphRAGError::Storage { .. }));
733 }
734
735 #[test]
736 fn test_error_severity() {
737 let config_error = GraphRAGError::Config {
738 message: "test".to_string(),
739 };
740 assert_eq!(config_error.severity(), ErrorSeverity::Critical);
741 assert!(!config_error.is_recoverable());
742
743 let warning_error = GraphRAGError::Retrieval {
744 message: "test".to_string(),
745 };
746 assert_eq!(warning_error.severity(), ErrorSeverity::Warning);
747 assert!(warning_error.is_recoverable());
748 }
749}