Skip to main content

rudof_rdf/rdf_core/
errors.rs

1use thiserror::Error;
2
3/// Represents all possible errors that can occur during RDF operations.
4#[derive(Error, Debug)]
5pub enum RDFError {
6    /// Default / fallback error.
7    #[error("{msg}")]
8    DefaultError { msg: String },
9
10    // ========================================================================
11    // Language and Literal Errors
12    // ========================================================================
13    /// Error parsing or validating a language tag in an RDF literal.
14    ///
15    /// # Fields
16    /// - `literal`: The complete literal value that contains the invalid language tag
17    /// - `language`: The invalid language tag that was encountered
18    /// - `error`: A detailed description of why the language tag is invalid
19    #[error("Error with language tag '{language}' in literal '{literal}': {error}")]
20    LanguageTagError {
21        literal: String,
22        language: String,
23        error: String,
24    },
25
26    // ========================================================================
27    // IRI Errors
28    // ========================================================================
29    /// Error obtaining a valid IRI from an IRI reference.
30    ///
31    /// This occurs when attempting to resolve an IRI reference (which may be
32    /// relative) into an absolute IRI, but the reference is invalid or cannot
33    /// be resolved.
34    ///
35    /// # Fields
36    /// - `iri_ref`: The IRI reference string that could not be resolved
37    #[error("Error obtaining IRI from IriRef: {iri_ref}")]
38    IriRefError { iri_ref: String },
39
40    /// Error parsing a string into a valid IRI.
41    ///
42    /// # Fields
43    /// - `iri`: The string that failed to parse as an IRI
44    /// - `error`: Details about the parsing failure
45    #[error("RDF error parsing iri {iri}: {error}")]
46    ParsingIri { iri: String, error: String },
47
48    // ========================================================================
49    // Conversion Errors
50    // ========================================================================
51    /// Generic conversion error for RDF data transformations.
52    ///
53    /// # Fields
54    /// - `msg`: A human-readable message describing the conversion failure
55    #[error("Conversion error {msg}")]
56    ConversionError { msg: String },
57
58    /// Error converting an RDF object node to a generic RDF term.
59    ///
60    /// # Fields
61    /// - `object`: String representation of the object that failed conversion
62    #[error("Converting Object {object} to RDF term")]
63    ObjectAsTerm { object: String },
64
65    /// Error converting a generic RDF term to a specific IRI type.
66    ///
67    /// # Fields
68    /// - `term`: String representation of the term that failed IRI conversion
69    #[error("Converting term {term} to IRI")]
70    TermAsIri { term: String },
71
72    /// Error converting a generic RDF term to a blank node.
73    ///
74    /// # Fields
75    /// - `term`: String representation of the term that failed blank node conversion
76    #[error("Converting term {term} to BNode")]
77    TermAsBNode { term: String },
78
79    /// Error converting a generic RDF term to a concrete IRI type (`IriS`).
80    ///
81    /// # Fields
82    /// - `term`: String representation of the term that failed IriS conversion
83    #[error("Converting term {term} to concrete IRI")]
84    TermAsIriS { term: String },
85
86    /// Error converting a generic RDF term to a literal.
87    ///
88    /// # Fields
89    /// - `term`: String representation of the term that failed literal conversion
90    #[error("Converting term {term} to Literal")]
91    TermAsLiteral { term: String },
92
93    /// Error converting a generic literal to a specific string literal type (`ConcreteLiteral`).
94    ///
95    /// # Fields
96    /// - `literal`: String representation of the literal that failed conversion
97    #[error("Converting literal {literal} to ConcreteLiteral")]
98    LiteralAsSLiteral { literal: String },
99
100    /// Error converting a generic RDF term to an object node.
101    ///
102    /// # Fields
103    /// - `term`: String representation of the term that failed object conversion
104    /// - `error`: Detailed description of the conversion failure
105    #[error("Converting Term {term} to Object: {error}")]
106    TermAsObject { term: String, error: String },
107
108    /// Error converting a generic RDF term to a subject node.
109    ///
110    /// # Fields
111    /// - `term`: String representation of the term that failed subject conversion
112    #[error("Converting term {term} to subject")]
113    TermAsSubject { term: String },
114
115    /// Error converting a generic RDF term to a language tag.
116    ///
117    /// This typically occurs when attempting to extract language information
118    /// from a term that is not a language-tagged string literal.
119    ///
120    /// # Fields
121    /// - `term`: String representation of the term that failed language tag conversion
122    #[error("Converting Term {term} to Lang")]
123    TermAsLang { term: String },
124
125    // ========================================================================
126    // Type Expectation Errors
127    // ========================================================================
128    /// Expected an IRI or blank node in subject/object position, but found a literal.
129    ///
130    /// # Fields
131    /// - `literal`: The literal value that appeared in an invalid position
132    #[error("Expected IRI or BlankNode, found literal: {literal}")]
133    ExpectedIriOrBlankNodeFoundLiteral { literal: String },
134
135    /// Expected an IRI or blank node, but found an RDF-star quoted triple.
136    ///
137    /// # Fields
138    /// - `subject`: Subject of the unexpected triple term
139    /// - `predicate`: Predicate of the unexpected triple term
140    /// - `object`: Object of the unexpected triple term
141    #[error("Expected IRI or BlankNode, found triple term ({subject},{predicate},{object})")]
142    ExpectedIriOrBlankNodeFoundTriple {
143        subject: String,
144        predicate: String,
145        object: String,
146    },
147
148    /// Error when expecting the focus node to be an IRI or blank node.
149    /// # Fields
150    /// - `term`: String representation of the focus node that is not an IRI or blank node
151    /// - `error`: Detailed description of why the conversion failed
152    #[error("Expected focus node to be an IRI or blank node, but found: {term}. Error: {error}")]
153    ExpectedIriOrBlankNodeError { term: String, error: String },
154
155    /// Error when expecting a literal but found a different term type.
156    ///
157    /// # Fields
158    /// - `term`: String representation of the term that is not a literal
159    #[error("Expected literal, but found: {term}")]
160    ExpectedLiteralError { term: String },
161
162    /// Error when expecting an integer literal but found a different literal type.
163    ///
164    /// # Fields
165    /// - `term`: String representation of the term that is not an integer/boolean literal
166    #[error("Expected integer or boolean literal, but found: {term}")]
167    ExpectedIntegerError { term: String },
168
169    /// Error when expecting an IRI but found a different term type.
170    ///
171    /// # Fields
172    /// - `term`: String representation of the term that is not an IRI
173    #[error("Expected IRI, but found: {term}")]
174    ExpectedIRIError { term: String },
175
176    /// Error when expecting a concrete literal but found a different literal type.
177    ///
178    /// # Fields
179    /// - `term`: String representation of the term that cannot be converted to concrete literal
180    #[error("Expected concrete literal, but found: {term}")]
181    ExpectedConcreteLiteralError { term: String },
182
183    /// Error when expecting a numeric literal but found a different literal type.
184    ///
185    /// # Fields
186    /// - `term`: String representation of the term that is not a numeric literal
187    #[error("Expected numeric literal, but found: {term}")]
188    ExpectedNumberError { term: String },
189
190    /// Error when expecting a boolean literal but found a different literal type.
191    ///
192    /// # Fields
193    /// - `term`: String representation of the term that is not a boolean literal
194    #[error("Expected boolean literal, but found: {term}")]
195    ExpectedBooleanError { term: String },
196
197    /// Error when expecting an object but found a different term type.
198    ///
199    /// # Fields
200    /// - `term`: String representation of the term that is not an object
201    #[error("Expected object, but found: {term}")]
202    ExpectedObjectError { term: String },
203
204    /// Error when expecting rdf:nil but found a different term type.
205    ///
206    /// # Fields
207    /// - `term`: String representation of the term that is not an rdf:nil
208    #[error("Expected rdf:nil, but found: {term}")]
209    ExpectedNilError { term: String },
210
211    // ========================================================================
212    // Comparison and Query Errors
213    // ========================================================================
214    /// Error comparing two RDF terms.
215    ///
216    /// # Fields
217    /// - `term1`: String representation of the first term
218    /// - `term2`: String representation of the second term
219    #[error("Comparison error: {term1} with {term2}")]
220    ComparisonError { term1: String, term2: String },
221
222    /// Error retrieving triples from an RDF graph or dataset.
223    ///
224    /// # Fields
225    /// - `error`: Detailed description of the triple retrieval failure
226    #[error("Obtaining triples from RDF: {error}")]
227    ObtainingTriples { error: String },
228
229    /// Error checking whether a specific triple exists in an RDF graph.
230    ///
231    /// # Fields
232    /// - `subject`: Subject of the triple being checked
233    /// - `predicate`: Predicate of the triple being checked
234    /// - `object`: Object of the triple being checked
235    /// - `error`: Detailed description of why the check failed
236    #[error("Error checking if RDF contains the triple <{subject}, {predicate}, {object}>: {error}")]
237    FailedCheckingAssertion {
238        subject: String,
239        predicate: String,
240        object: String,
241        error: String,
242    },
243
244    /// Error finding subjects that match a given predicate-object pattern.
245    ///
246    /// # Fields
247    /// - `predicate`: The predicate being queried
248    /// - `object`: The object being queried
249    /// - `error`: Detailed description of the query failure
250    #[error("Error obtaining subjects for predicate {predicate} and object {object}: {error}")]
251    ErrorSubjectsFor {
252        predicate: String,
253        object: String,
254        error: String,
255    },
256
257    /// Error finding objects that match a given subject-predicate pattern.
258    ///
259    /// # Fields
260    /// - `subject`: The subject being queried
261    /// - `predicate`: The predicate being queried
262    /// - `error`: Detailed description of the query failure
263    #[error("Error obtaining objects for subject {subject} and predicate {predicate}: {error}")]
264    ErrorObjectsFor {
265        subject: String,
266        predicate: String,
267        error: String,
268    },
269
270    // ========================================================================
271    // Output/Serialization Errors
272    // ========================================================================
273    /// Error formatting SPARQL query results as a table.
274    ///
275    /// # Fields
276    /// - `error`: Detailed description of the table writing failure
277    #[error("Writing query results in table: {error}")]
278    WritingTableError { error: String },
279
280    // ========================================================================
281    // Focus Node Errors
282    // ========================================================================
283    /// Error when a parsing operation requires a focus node but none is set.
284    #[error("No focus node set. A focus node is required for this operation.")]
285    NoFocusNodeError,
286
287    /// Error when expecting the focus node to be a valid RDF subject.
288    ///
289    /// # Fields
290    /// - `node`: String representation of the focus node that is not a valid subject
291    /// - `context`: The operation or context where the subject was expected
292    #[error("Expected focus node to be a subject (IRI or blank node), but found: {node} in context: {context}")]
293    ExpectedSubjectError { node: String, context: String },
294
295    // ========================================================================
296    // Parse Errors
297    // ========================================================================
298    /// Error when attempting to parse or process an unsupported RDF format.
299    ///
300    /// # Fields
301    /// - `format`: The unsupported format identifier that was requested
302    #[error("Format {format} not supported")]
303    NotSupportedRDFFormatError { format: String },
304
305    /// Error when both branches of an `or` combinator fail.
306    ///
307    /// # Fields
308    /// - `err1`: The error from the first parser that was tried
309    /// - `err2`: The error from the second (fallback) parser
310    #[error("Both branches of OR combinator failed. First: {err1}, Second: {err2}")]
311    FailedOrError { err1: Box<RDFError>, err2: Box<RDFError> },
312
313    /// Error when a `not` combinator's inner parser unexpectedly succeeds.
314    ///
315    /// # Fields
316    /// - `value`: String representation of the unexpected successful parse result
317    #[error("NOT combinator failed: parser unexpectedly succeeded with value: {value}")]
318    FailedNotError { value: String },
319
320    /// Error when an RDF node cannot be parsed as a valid SHACL path.
321    ///
322    /// # Fields
323    /// - `node`: String representation of the RDF node being parsed
324    /// - `context`: Where the parsing was attempted (e.g. function name)
325    /// - `error`: The underlying parsing error
326    #[error("Invalid SHACL path at node {node}: {error}")]
327    InvalidSHACLPathError { node: String, error: Box<RDFError> },
328
329    /// Error when an opaque parser fails to execute or provide a valid parser.
330    ///
331    /// # Fields
332    /// - `msg`: A detailed description of why the opaque parser failed
333    /// - `context`: Optional context about where in the parsing process the failure occurred
334    #[error("Opaque parser failed: {msg}{}", context.as_ref().map(|c| format!(" (context: {})", c)).unwrap_or_default())]
335    FailedOpaqueError { msg: String, context: Option<String> },
336
337    /// Error when a parser explicitly fails with a custom message.
338    ///
339    /// # Fields
340    /// - `msg`: The custom error message describing why the parser failed
341    #[error("Parse failed: {msg}")]
342    ParseFailError { msg: String },
343
344    /// Error when a conditional validation fails.
345    ///
346    /// # Fields
347    /// - `msg`: The error message describing which condition failed
348    #[error("Condition validation failed: {msg}")]
349    FailedCondError { msg: String },
350
351    /// Error when parsing an RDF list that contains a cycle.
352    ///
353    /// # Fields
354    /// - `node`: String representation of the node that creates the cycle
355    #[error("Recursive RDF list detected: node {node} was already visited, creating a cycle")]
356    RecursiveRDFListError { node: String },
357
358    /// Error when attempting to convert a term to an RDF node (Object) fails.
359    ///
360    /// # Fields
361    /// - `term`: String representation of the term that failed conversion
362    #[error("Failed to convert term to RDF node: {term}")]
363    FailedTermToRDFNodeError { term: String },
364
365    // Error when attempting to convert a subject to an RDF node (Object) fails.
366    ///
367    /// # Fields
368    /// - `subject`: String representation of the term that failed conversion
369    #[error("Failed to convert subject to RDF node: {subject}")]
370    FailedSubjectToRDFNodeError { subject: String },
371
372    /// Error when attempting to convert an RDF subject to an IRI or blank node.
373    ///
374    /// # Fields
375    /// - `subject`: String representation of the subject that failed conversion
376    #[error("Failed to convert subject to IRI or blank node: {subject}")]
377    SubjectToIriOrBlankNodeError { subject: String },
378
379    /// Error when expecting the focus node to be a valid RDF subject.
380    ///
381    /// # Fields
382    /// - `focus`: String representation of the focus node that is not a valid subject
383    #[error("Expected focus node to be a subject (IRI or blank node), but found: {focus}")]
384    ExpectedFocusAsSubjectError { focus: String },
385
386    /// Error when a property has more than one value but exactly one was expected.
387    ///
388    /// # Fields
389    /// - `node`: String representation of the node being queried
390    /// - `pred`: The property/predicate that has multiple values
391    /// - `value1`: String representation of the first value found
392    /// - `value2`: String representation of the second value found
393    #[error("Node {node} has more than one value for predicate {pred}: found at least {value1} and {value2}")]
394    MoreThanOneValuePredicateError {
395        node: String,
396        pred: String,
397        value1: String,
398        value2: String,
399    },
400
401    /// Error when a property has no values but at least one was expected.
402    ///
403    /// # Fields
404    /// - `node`: String representation of the node being queried
405    /// - `pred`: The property/predicate that has no values
406    #[error("Node {node} has no values for predicate {pred}")]
407    NoValuesPredicateError { node: String, pred: String },
408
409    /// Error when a property has no values (debug version with neighborhood info).
410    ///
411    /// # Fields
412    /// - `node`: String representation of the node being queried
413    /// - `pred`: The property/predicate that has no values
414    /// - `outgoing_arcs`: String representation of all outgoing arcs from the node
415    #[error("Node {node} has no values for predicate {pred}. Outgoing arcs: {outgoing_arcs}")]
416    NoValuesPredicateDebugError {
417        node: String,
418        pred: String,
419        outgoing_arcs: String,
420    },
421
422    /// Error when failing to obtain outgoing arcs from a focus node.
423    ///
424    /// # Fields
425    /// - `focus`: String representation of the focus node
426    /// - `error`: Detailed description of why obtaining outgoing arcs failed
427    #[error("Error obtaining outgoing arcs from node {focus}: {error}")]
428    OutgoingArcsError { focus: String, error: String },
429
430    /// Error when a node fails to satisfy a predicate condition.
431    ///
432    /// # Fields
433    /// - `condition_name`: The name/description of the condition that was not satisfied
434    /// - `node`: String representation of the node that failed the condition
435    #[error("Node {node} does not satisfy condition: {condition_name}")]
436    NodeDoesntSatisfyConditionError { condition_name: String, node: String },
437
438    /// Error when no instances of a specified type are found in the RDF data.
439    ///
440    /// # Fields
441    /// - `object`: The IRI of the expected type/class that has no instances
442    #[error("No instances found for type: {object}")]
443    FailedInstancesOfError { object: String },
444
445    /// Error when a required property is not found on a node.
446    ///
447    /// # Fields
448    /// - `property`: The predicate that was expected
449    /// - `subject`: The subject node where the property was searched
450    /// - `err`: Underlying error
451    #[error("Property '{property}' not found in subject '{subject}': {err}")]
452    PropertyNotFoundError {
453        property: String,
454        subject: String,
455        err: Box<RDFError>,
456    },
457
458    /// Error when attempting to convert a term into an RDF Object.
459    ///
460    /// # Fields
461    /// - `term`: String representation of the term that failed conversion
462    #[error("Failed to convert term to Object: {term}")]
463    FailedTermToObjectError { term: String },
464
465    /// Error when more than one instance of a given type is found when exactly one was expected.
466    ///
467    /// # Fields
468    /// - `type_iri`: The IRI of the type that has multiple instances
469    #[error("More than one instance found for type: {type_iri}")]
470    MoreThanOneInstanceError { type_iri: String },
471
472    /// Error when an RDF node has a type different from the expected one.
473    ///
474    /// # Fields
475    /// - `expected`: String representation of the expected RDF type
476    /// - `actual`: String representation of the actual RDF type found
477    #[error("Type mismatch: expected {expected}, but found {actual}")]
478    TypeMismatchError { expected: String, actual: String },
479
480    /// Error when a conditional parser predicate evaluates to false.
481    ///
482    /// # Fields
483    /// - `msg`: Explanation of why the condition failed
484    #[error("Conditional parser failed: {msg}")]
485    FailedConditionalError { msg: String },
486
487    // ========================================================================
488    // Configuration Errors
489    // ========================================================================
490    /// Error reading the configuration file from disk.
491    ///
492    /// # Fields
493    /// - `path_name`: The path of the file that could not be read
494    /// - `error`: The underlying I/O error
495    #[error("Reading path {path_name:?} error: {error:?}")]
496    ReadingConfigError { path_name: String, error: std::io::Error },
497
498    /// Error parsing the TOML configuration file.
499    ///
500    /// # Fields
501    /// - `path_name`: The path of the TOML file that failed to parse
502    /// - `error`: The underlying TOML parsing error
503    #[error("Reading TOML from {path_name:?}. Error: {error:?}")]
504    TomlError { path_name: String, error: toml::de::Error },
505
506    /// Error converting a string to a valid IRI for an endpoint.
507    ///
508    /// # Fields
509    /// - `error`: Detailed description of the IRI parsing failure
510    /// - `str`: The string that failed to parse as an IRI
511    #[error("Converting to IRI the string {str}. Error: {error}")]
512    ConvertingIriEndpoint { error: String, str: String },
513}