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}