satay_codegen/error/validation.rs
1/// Errors that can occur while validating an OpenAPI document.
2///
3/// This enum is [`non_exhaustive`](https://doc.rust-lang.org/reference/attributes/type_system.html)
4/// so new variants may be added in future releases without a semver break.
5#[derive(Debug, thiserror::Error)]
6#[non_exhaustive]
7pub enum ValidationError {
8 // -- Document and component shape validation --
9 /// The OpenAPI version is not supported.
10 ///
11 /// Error message: `unsupported OpenAPI version `{version}`; Satay supports OpenAPI 3.1`
12 #[error("unsupported OpenAPI version `{version}`; Satay supports OpenAPI 3.1")]
13 UnsupportedOpenApiVersion { version: String },
14
15 /// A schema component uses a type that is not supported.
16 ///
17 /// Error message: `unsupported type `{kind}` in schema `{schema}``
18 #[error("unsupported type `{kind}` in schema `{schema}`")]
19 UnsupportedComponentType { schema: String, kind: String },
20
21 /// A schema component is missing a required `type`, `$ref`, `enum`, or `properties` declaration.
22 ///
23 /// Error message: `schema `{schema}` must declare `type`, `$ref`, `enum`, or `properties``
24 #[error("schema `{schema}` must declare `type`, `$ref`, `enum`, or `properties`")]
25 MissingComponentSchemaType { schema: String },
26
27 /// An object schema is missing the required `properties` field.
28 ///
29 /// Error message: `object schema `{schema}` must declare `properties``
30 #[error("object schema `{schema}` must declare `properties`")]
31 MissingObjectProperties { schema: String },
32
33 /// The OpenAPI document is missing the required `paths` field.
34 ///
35 /// Error message: `OpenAPI document must declare `paths``
36 #[error("OpenAPI document must declare `paths`")]
37 MissingPaths,
38
39 // -- Enum and schema type validation --
40 /// A schema uses an enum with a non-string type.
41 ///
42 /// Error message: `{context} uses enum type `{kind}`; only string enums are supported`
43 #[error("{context} uses enum type `{kind}`; only string enums are supported")]
44 UnsupportedEnumType { context: String, kind: String },
45
46 /// A schema declares an enum that is not an array.
47 ///
48 /// Error message: `{context} has a non-array enum`
49 #[error("{context} has a non-array enum")]
50 NonArrayEnum { context: String },
51
52 /// A schema declares an enum with no values.
53 ///
54 /// Error message: `{context} has an empty enum`
55 #[error("{context} has an empty enum")]
56 EmptyEnum { context: String },
57
58 /// A schema enum contains a non-string value.
59 ///
60 /// Error message: `{context} contains a non-string enum value; only string enums are supported`
61 #[error("{context} contains a non-string enum value; only string enums are supported")]
62 NonStringEnumValue { context: String },
63
64 /// An `x-satay.enum-variants` value is not an object.
65 ///
66 /// Error message: `{context}.x-satay.enum-variants must be an object`
67 #[error("{context}.x-satay.enum-variants must be an object")]
68 InvalidSatayEnumVariants { context: String },
69
70 /// An `x-satay.enum-variants` entry points at a value that is not in the enum.
71 ///
72 /// Error message: `{context}.x-satay.enum-variants contains `{wire_name}`, which is not declared in the enum`
73 #[error(
74 "{context}.x-satay.enum-variants contains `{wire_name}`, which is not declared in the enum"
75 )]
76 UnknownSatayEnumVariantValue { context: String, wire_name: String },
77
78 /// An `x-satay.enum-variants` entry has a non-string Rust variant name.
79 ///
80 /// Error message: `{context}.x-satay.enum-variants[{wire_name:?}] must be a string`
81 #[error("{context}.x-satay.enum-variants[{wire_name:?}] must be a string")]
82 InvalidSatayEnumVariantName { context: String, wire_name: String },
83
84 /// Two `x-satay.enum-variants` entries produce the same Rust variant name.
85 ///
86 /// Error message: `{context}.x-satay.enum-variants maps multiple values to `{rust_name}``
87 #[error("{context}.x-satay.enum-variants maps multiple values to `{rust_name}`")]
88 DuplicateSatayEnumVariantName { context: String, rust_name: String },
89
90 /// A schema has a `required` field that is not an array.
91 ///
92 /// Error message: `{context} has a non-array `required` field`
93 #[error("{context} has a non-array `required` field")]
94 NonArrayRequired { context: String },
95
96 /// A schema `required` array contains a non-string element.
97 ///
98 /// Error message: `{context} has a non-string required field name`
99 #[error("{context} has a non-string required field name")]
100 NonStringRequiredField { context: String },
101
102 /// An integer schema uses an unsupported format.
103 ///
104 /// Error message: `{context} uses unsupported integer format `{format}``
105 #[error("{context} uses unsupported integer format `{format}`")]
106 UnsupportedIntegerFormat { context: String, format: String },
107
108 /// A number schema uses an unsupported format.
109 ///
110 /// Error message: `{context} uses unsupported number format `{format}``
111 #[error("{context} uses unsupported number format `{format}`")]
112 UnsupportedNumberFormat { context: String, format: String },
113
114 /// An `x-satay.parse-as` value is not a supported target type.
115 ///
116 /// Error message: `{context} uses unsupported x-satay.parse-as `{parse_as}``
117 #[error("{context} uses unsupported x-satay.parse-as `{parse_as}`")]
118 UnsupportedSatayParseAs { context: String, parse_as: String },
119
120 /// An `x-satay.parse-as` value is not a string.
121 ///
122 /// Error message: `{context}.x-satay.parse-as must be a string`
123 #[error("{context}.x-satay.parse-as must be a string")]
124 InvalidSatayParseAs { context: String },
125
126 /// `x-satay.parse-as` was applied to an unsupported wire schema.
127 ///
128 /// Error message: `{context} uses x-satay.parse-as `{parse_as}` on `{kind}`; supported parse-as wire schemas are string schemas, plus integer schemas for bool`
129 #[error(
130 "{context} uses x-satay.parse-as `{parse_as}` on `{kind}`; supported parse-as wire schemas are string schemas, plus integer schemas for bool"
131 )]
132 SatayParseAsRequiresString {
133 context: String,
134 parse_as: String,
135 kind: String,
136 },
137
138 /// An `x-satay.integer-type` value is not a supported Rust integer type.
139 ///
140 /// Error message: `{context} uses unsupported x-satay.integer-type `{integer_type}``
141 #[error("{context} uses unsupported x-satay.integer-type `{integer_type}`")]
142 UnsupportedSatayIntegerType {
143 context: String,
144 integer_type: String,
145 },
146
147 /// An `x-satay.integer-type` value is not a string.
148 ///
149 /// Error message: `{context}.x-satay.integer-type must be a string`
150 #[error("{context}.x-satay.integer-type must be a string")]
151 InvalidSatayIntegerType { context: String },
152
153 /// `x-satay.integer-type` was applied to a non-integer schema.
154 ///
155 /// Error message: `{context} uses x-satay.integer-type `{integer_type}` on `{kind}`; supported integer-type wire schemas are integer schemas and string schemas with x-satay.parse-as integer-range`
156 #[error(
157 "{context} uses x-satay.integer-type `{integer_type}` on `{kind}`; supported integer-type wire schemas are integer schemas and string schemas with x-satay.parse-as integer-range"
158 )]
159 SatayIntegerTypeRequiresInteger {
160 context: String,
161 integer_type: String,
162 kind: String,
163 },
164
165 /// An array schema is missing the required `items` field.
166 ///
167 /// Error message: `{context} array schema must declare `items``
168 #[error("{context} array schema must declare `items`")]
169 MissingArrayItems { context: String },
170
171 /// A schema defines an inline object instead of using a `$ref`.
172 ///
173 /// Error message: `{context} is an inline object schema; move it to components/schemas and use `$ref``
174 #[error("{context} is an inline object schema; move it to components/schemas and use `$ref`")]
175 InlineObjectSchema { context: String },
176
177 /// An object schema has no properties (i.e. acts as a map/dictionary), which is unsupported.
178 ///
179 /// Error message: `{context} is an object without properties; map/object schemas are not supported yet`
180 #[error("{context} is an object without properties; map/object schemas are not supported yet")]
181 UnsupportedMapObjectSchema { context: String },
182
183 /// A schema uses an unsupported type.
184 ///
185 /// Error message: `{context} uses unsupported schema type `{kind}``
186 #[error("{context} uses unsupported schema type `{kind}`")]
187 UnsupportedSchemaType { context: String, kind: String },
188
189 /// A schema is missing a required `type`, `$ref`, or `enum` declaration.
190 ///
191 /// Error message: `{context} must declare `type`, `$ref`, or `enum``
192 #[error("{context} must declare `type`, `$ref`, or `enum`")]
193 MissingSchemaType { context: String },
194
195 /// A JSON Schema boolean schema was used; Satay has no IR equivalent yet.
196 ///
197 /// Error message: `{context} is a boolean schema; boolean JSON Schemas are not supported yet`
198 #[error("{context} is a boolean schema; boolean JSON Schemas are not supported yet")]
199 UnsupportedBooleanSchema { context: String },
200
201 /// A schema type array contains more than one non-null type.
202 ///
203 /// Error message: `{context} declares multiple non-null schema types; Satay supports at most one plus null`
204 #[error(
205 "{context} declares multiple non-null schema types; Satay supports at most one plus null"
206 )]
207 MultipleNonNullSchemaTypesUnsupported { context: String },
208
209 /// A schema uses a composition keyword (`allOf`, `anyOf`, `oneOf`) that is outside MVP scope.
210 ///
211 /// Error message: `{context} uses `{keyword}`, which is not in the MVP scope`
212 #[error("{context} uses `{keyword}`, which is not in the MVP scope")]
213 UnsupportedComposition {
214 context: String,
215 keyword: &'static str,
216 },
217
218 /// An `allOf` schema combines supported struct flattening with another schema keyword.
219 ///
220 /// Error message: `{context} uses `allOf` with `{keyword}`; only object branch flattening is supported`
221 #[error("{context} uses `allOf` with `{keyword}`; only object branch flattening is supported")]
222 UnsupportedAllOfSiblingKeyword { context: String, keyword: String },
223
224 /// An `allOf` branch cannot be flattened into a generated Rust struct.
225 ///
226 /// Error message: `{context}.allOf[{index}] must be a local component schema reference or object schema with properties`
227 #[error(
228 "{context}.allOf[{index}] must be a local component schema reference or object schema with properties"
229 )]
230 UnsupportedAllOfBranch { context: String, index: usize },
231
232 /// Two `allOf` branches declare the same object property.
233 ///
234 /// Error message: `{context} declares duplicate `allOf` property `{property}``
235 #[error("{context} declares duplicate `allOf` property `{property}`")]
236 DuplicateAllOfProperty { context: String, property: String },
237
238 /// `allOf` component schemas form a recursive flattening cycle.
239 ///
240 /// Error message: `{context} forms a recursive `allOf` cycle through schema `{schema}``
241 #[error("{context} forms a recursive `allOf` cycle through schema `{schema}`")]
242 RecursiveAllOf { context: String, schema: String },
243
244 /// An `anyOf` schema combines a supported union with another schema keyword.
245 ///
246 /// Error message: `{context} uses `anyOf` with `{keyword}`; only annotation siblings are supported`
247 #[error("{context} uses `anyOf` with `{keyword}`; only annotation siblings are supported")]
248 UnsupportedAnyOfSiblingKeyword { context: String, keyword: String },
249
250 /// An `anyOf` branch is not a local component schema reference.
251 ///
252 /// Error message: `{context}.anyOf[{index}] must be a local component schema reference`
253 #[error("{context}.anyOf[{index}] must be a local component schema reference")]
254 UnsupportedAnyOfBranch { context: String, index: usize },
255
256 /// A composition schema declares no branches.
257 ///
258 /// Raised for empty `anyOf` and, today, for empty component `allOf` that is routed
259 /// through the shared empty composition-shape check.
260 ///
261 /// Error message: `{context} must declare at least one `anyOf` branch`
262 #[error("{context} must declare at least one `anyOf` branch")]
263 EmptyAnyOf { context: String },
264
265 /// `anyOf` component schemas form a recursive union cycle.
266 ///
267 /// Error message: `{context} forms a recursive `anyOf` cycle through schema `{schema}``
268 #[error("{context} forms a recursive `anyOf` cycle through schema `{schema}`")]
269 RecursiveAnyOf { context: String, schema: String },
270
271 /// A discriminator union does not use exactly one non-empty `anyOf` or `oneOf` branch list.
272 ///
273 /// Error message: `{context} discriminator unions must declare exactly one non-empty `anyOf` or `oneOf` branch list`
274 #[error(
275 "{context} discriminator unions must declare exactly one non-empty `anyOf` or `oneOf` branch list"
276 )]
277 InvalidDiscriminatorUnion { context: String },
278
279 /// A discriminator union branch is not a local component schema reference.
280 ///
281 /// Error message: `{context}.{keyword}[{index}] must be a local component schema reference when using `discriminator``
282 #[error(
283 "{context}.{keyword}[{index}] must be a local component schema reference when using `discriminator`"
284 )]
285 UnsupportedDiscriminatorBranch {
286 context: String,
287 keyword: &'static str,
288 index: usize,
289 },
290
291 /// A discriminator union branch target does not generate as an object struct.
292 ///
293 /// Error message: `{context} discriminator branch `{schema}` must be an object struct component`
294 #[error("{context} discriminator branch `{schema}` must be an object struct component")]
295 DiscriminatorBranchNotObject { context: String, schema: String },
296
297 /// A discriminator branch object contains the discriminator property.
298 ///
299 /// Error message: `{context} discriminator branch `{schema}` contains discriminator property `{property}``
300 #[error(
301 "{context} discriminator branch `{schema}` contains discriminator property `{property}`"
302 )]
303 DiscriminatorPropertyConflict {
304 context: String,
305 schema: String,
306 property: String,
307 },
308
309 /// A discriminator mapping entry targets a non-local schema or a schema outside the union branches.
310 ///
311 /// Error message: `{context}.discriminator.mapping[{value:?}] targets `{target}`, which is not a local union branch schema`
312 #[error(
313 "{context}.discriminator.mapping[{value:?}] targets `{target}`, which is not a local union branch schema"
314 )]
315 InvalidDiscriminatorMapping {
316 context: String,
317 value: String,
318 target: String,
319 },
320
321 /// Multiple discriminator mapping values target the same union branch schema.
322 ///
323 /// Error message: `{context}.discriminator.mapping maps multiple values to branch schema `{schema}``
324 #[error("{context}.discriminator.mapping maps multiple values to branch schema `{schema}`")]
325 DuplicateDiscriminatorMapping { context: String, schema: String },
326
327 /// Multiple discriminator branches resolve to the same discriminator value after implicit defaults are applied.
328 ///
329 /// Error message: `{context}.discriminator resolves multiple branch schemas to value `{value}``
330 #[error("{context}.discriminator resolves multiple branch schemas to value `{value}`")]
331 DuplicateDiscriminatorValue { context: String, value: String },
332
333 // -- Schema constraint validation --
334 /// A string schema specifies a `minLength` greater than its `maxLength`.
335 ///
336 /// Error message: `{context} has minLength {min_length} greater than maxLength {max_length}`
337 #[error("{context} has minLength {min_length} greater than maxLength {max_length}")]
338 InvalidStringLengthBounds {
339 context: String,
340 min_length: u64,
341 max_length: u64,
342 },
343
344 /// A schema uses `uniqueItems`, which cannot be enforced by generated `Vec`-backed types.
345 ///
346 /// Error message: `{context} uses `uniqueItems`; generated Vec-backed types cannot enforce uniqueness yet`
347 #[error(
348 "{context} uses `uniqueItems`; generated Vec-backed types cannot enforce uniqueness yet"
349 )]
350 UniqueItemsUnsupported { context: String },
351
352 /// An array schema specifies `minItems` greater than `maxItems`.
353 ///
354 /// Error message: `{context} has minItems {min_items} greater than maxItems {max_items}`
355 #[error("{context} has minItems {min_items} greater than maxItems {max_items}")]
356 InvalidArrayLengthBounds {
357 context: String,
358 min_items: u64,
359 max_items: u64,
360 },
361
362 /// A schema uses a keyword that is not safely supported.
363 ///
364 /// Error message: `{context} uses `{keyword}`, which is not safely supported yet`
365 #[error("{context} uses `{keyword}`, which is not safely supported yet")]
366 UnsupportedKeyword {
367 context: String,
368 keyword: &'static str,
369 },
370
371 /// A schema keyword that must be a non-negative integer has an invalid value.
372 ///
373 /// Error message: `{context}.{keyword} must be a non-negative integer`
374 #[error("{context}.{keyword} must be a non-negative integer")]
375 InvalidNonNegativeIntegerKeyword {
376 context: String,
377 keyword: &'static str,
378 },
379
380 /// A schema keyword that must be a boolean has an invalid value.
381 ///
382 /// Error message: `{context}.{keyword} must be a boolean`
383 #[error("{context}.{keyword} must be a boolean")]
384 InvalidBooleanKeyword {
385 context: String,
386 keyword: &'static str,
387 },
388
389 /// An `exclusiveMinimum`/`exclusiveMaximum` keyword is present but the corresponding bound is missing.
390 ///
391 /// Error message: `{context}.{exclusive_keyword} requires `{keyword}``
392 #[error("{context}.{exclusive_keyword} requires `{keyword}`")]
393 ExclusiveLimitRequiresBound {
394 context: String,
395 exclusive_keyword: &'static str,
396 keyword: &'static str,
397 },
398
399 /// A schema keyword that must be a finite number has a non-finite value.
400 ///
401 /// Error message: `{context}.{keyword} must be a finite number`
402 #[error("{context}.{keyword} must be a finite number")]
403 InvalidFiniteNumberKeyword {
404 context: String,
405 keyword: &'static str,
406 },
407
408 /// A value expected to be an integer is not.
409 ///
410 /// Error message: `{context} must be an integer`
411 #[error("{context} must be an integer")]
412 ExpectedInteger { context: String },
413
414 /// Integer bounds (minimum/maximum) do not permit any value.
415 ///
416 /// Error message: `{context} integer bounds do not allow any value`
417 #[error("{context} integer bounds do not allow any value")]
418 EmptyIntegerBounds { context: String },
419
420 /// An exclusive integer minimum overflows `i64`.
421 ///
422 /// Error message: `exclusive integer minimum overflows`
423 #[error("exclusive integer minimum overflows")]
424 ExclusiveIntegerMinimumOverflow,
425
426 /// An exclusive integer maximum overflows `i64`.
427 ///
428 /// Error message: `exclusive integer maximum overflows`
429 #[error("exclusive integer maximum overflows")]
430 ExclusiveIntegerMaximumOverflow,
431
432 /// Number bounds (minimum/maximum) do not permit any value.
433 ///
434 /// Error message: `{context} number bounds do not allow any value`
435 #[error("{context} number bounds do not allow any value")]
436 EmptyNumberBounds { context: String },
437
438 // -- Operation, parameter, and response validation --
439 /// An operation does not declare any responses.
440 ///
441 /// Error message: `operation `{operation_id}` must declare responses`
442 #[error("operation `{operation_id}` must declare responses")]
443 MissingOperationResponses { operation_id: String },
444
445 /// A value expected to be an array is not.
446 ///
447 /// Error message: `{context} must be an array`
448 #[error("{context} must be an array")]
449 ExpectedArray { context: String },
450
451 /// A parameter uses an unsupported location (e.g. cookie) instead of path, query, or header.
452 ///
453 /// Error message: `{context} parameter `{wire_name}` is in `{location}`; only path, query, and header parameters are supported`
454 #[error(
455 "{context} parameter `{wire_name}` is in `{location}`; only path, query, and header parameters are supported"
456 )]
457 UnsupportedParameterLocation {
458 context: String,
459 wire_name: String,
460 location: String,
461 },
462
463 /// A parameter uses `content` instead of `schema`.
464 ///
465 /// Error message: `{context} parameter `{wire_name}` uses `content`; schema parameters are required`
466 #[error("{context} parameter `{wire_name}` uses `content`; schema parameters are required")]
467 ContentParameterUnsupported { context: String, wire_name: String },
468
469 /// A parameter is missing a required `schema` declaration.
470 ///
471 /// Error message: `{context} parameter `{wire_name}` must declare schema`
472 #[error("{context} parameter `{wire_name}` must declare schema")]
473 MissingParameterSchema { context: String, wire_name: String },
474
475 /// A parameter is nullable, which is not supported.
476 ///
477 /// Error message: `parameter `{wire_name}` is nullable; nullable parameters are not supported`
478 #[error("parameter `{wire_name}` is nullable; nullable parameters are not supported")]
479 NullableParameterUnsupported { wire_name: String },
480
481 /// A parameter uses `anyOf`, which is not supported for URI/header encoding yet.
482 ///
483 /// Error message: `parameter `{wire_name}` uses `anyOf`; anyOf parameters are not supported yet`
484 #[error("parameter `{wire_name}` uses `anyOf`; anyOf parameters are not supported yet")]
485 AnyOfParameterUnsupported { wire_name: String },
486
487 /// A path parameter is an array, which is not supported.
488 ///
489 /// Error message: `path parameter `{wire_name}` is an array; array path parameter styles are not supported`
490 #[error(
491 "path parameter `{wire_name}` is an array; array path parameter styles are not supported"
492 )]
493 ArrayPathParameterUnsupported { wire_name: String },
494
495 /// A header parameter is an array, which is not supported.
496 ///
497 /// Error message: `header parameter `{wire_name}` is an array; array header parameter styles are not supported`
498 #[error(
499 "header parameter `{wire_name}` is an array; array header parameter styles are not supported"
500 )]
501 ArrayHeaderParameterUnsupported { wire_name: String },
502
503 /// A path parameter does not set `required: true`.
504 ///
505 /// Error message: `path parameter `{wire_name}` must set required: true`
506 #[error("path parameter `{wire_name}` must set required: true")]
507 PathParameterNotRequired { wire_name: String },
508
509 /// A context is missing a required `content` declaration.
510 ///
511 /// Error message: `{context} must declare content`
512 #[error("{context} must declare content")]
513 MissingContent { context: String },
514
515 /// A context is missing the required `application/json` content type.
516 ///
517 /// Error message: `{context} must declare application/json content`
518 #[error("{context} must declare application/json content")]
519 MissingJsonContent { context: String },
520
521 /// A context's `application/json` content is missing a schema.
522 ///
523 /// Error message: `{context} application/json content must declare schema`
524 #[error("{context} application/json content must declare schema")]
525 MissingJsonSchema { context: String },
526
527 /// A response body uses the `default` status, which is not yet supported for decoding.
528 ///
529 /// Error message: `{context} contains a default response body; default response decoding is not supported yet`
530 #[error(
531 "{context} contains a default response body; default response decoding is not supported yet"
532 )]
533 DefaultResponseBodyUnsupported { context: String },
534
535 /// A response contains an invalid HTTP status code string.
536 ///
537 /// Error message: `{context} contains invalid status code `{status}``
538 #[error("{context} contains invalid status code `{status}`")]
539 InvalidStatusCode { context: String, status: String },
540
541 /// A response contains a status code outside the valid 100–599 range.
542 ///
543 /// Error message: `{context} contains out-of-range status code `{status_code}``
544 #[error("{context} contains out-of-range status code `{status_code}`")]
545 OutOfRangeStatusCode { context: String, status_code: u16 },
546
547 /// A response for a given status code is missing `application/json` content.
548 ///
549 /// Error message: `{context} {status} response must declare application/json content`
550 #[error("{context} {status} response must declare application/json content")]
551 MissingResponseJsonContent { context: String, status: String },
552
553 /// A path template contains a parameter that is never closed.
554 ///
555 /// Error message: `path `{path}` contains an unclosed parameter`
556 #[error("path `{path}` contains an unclosed parameter")]
557 UnclosedPathParameter { path: String },
558
559 /// A path template contains an empty parameter (e.g. `{}`).
560 ///
561 /// Error message: `path `{path}` contains an empty parameter`
562 #[error("path `{path}` contains an empty parameter")]
563 EmptyPathParameter { path: String },
564
565 /// A path template references a parameter that is not declared in the operation's parameters.
566 ///
567 /// Error message: `path `{path}` uses parameter `{name}` but it is not declared`
568 #[error("path `{path}` uses parameter `{name}` but it is not declared")]
569 UndeclaredPathParameter { path: String, name: String },
570
571 /// A parameter is declared for a path but never used in the path template.
572 ///
573 /// Error message: `path parameter `{name}` is declared but not used in path `{path}``
574 #[error("path parameter `{name}` is declared but not used in path `{path}`")]
575 UnusedPathParameter { path: String, name: String },
576
577 // -- Reference resolution and JSON shape validation --
578 /// A `$ref` could not be resolved because the referenced component failed validation.
579 ///
580 /// Error message: `failed to resolve reference `{reference}` in {context}: {source}`
581 #[error("failed to resolve reference `{reference}` in {context}: {source}")]
582 ResolveReference {
583 reference: String,
584 context: String,
585 #[source]
586 source: Box<ValidationError>,
587 },
588
589 /// A reference points to an external document; only local (`#`) references are supported.
590 ///
591 /// Error message: `only local references are supported`
592 #[error("only local references are supported")]
593 NonLocalReference,
594
595 /// A local reference is not a valid JSON pointer.
596 ///
597 /// Error message: `local reference must be a JSON pointer`
598 #[error("local reference must be a JSON pointer")]
599 InvalidLocalReference,
600
601 /// A JSON pointer is missing a required token segment.
602 ///
603 /// Error message: `missing `{token}``
604 #[error("missing `{token}`")]
605 MissingJsonPointerToken { token: String },
606
607 /// A `$ref` does not point to the expected `#/components/{section}/…` path.
608 ///
609 /// Error message: `reference `{reference}` must point to #/components/{section}/...`
610 #[error("reference `{reference}` must point to #/components/{section}/...")]
611 InvalidComponentReference {
612 reference: String,
613 section: &'static str,
614 },
615
616 /// A local `$ref` chain references itself.
617 ///
618 /// Error message: `circular reference `{reference}``
619 #[error("circular reference `{reference}`")]
620 CircularReference { reference: String },
621
622 /// A value expected to be an object is not.
623 ///
624 /// Error message: `{context} must be an object`
625 #[error("{context} must be an object")]
626 ExpectedObject { context: String },
627
628 /// A nested field expected to be an object is not.
629 ///
630 /// Error message: `{context}.{field} must be an object`
631 #[error("{context}.{field} must be an object")]
632 ExpectedObjectField {
633 context: String,
634 field: &'static str,
635 },
636}