apache_avro/
error.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::{
19    schema::{Name, Schema, SchemaKind},
20    types::{Value, ValueKind},
21};
22use std::{error::Error as _, fmt};
23
24#[derive(thiserror::Error)]
25pub enum Error {
26    #[error("Bad Snappy CRC32; expected {expected:x} but got {actual:x}")]
27    SnappyCrc32 { expected: u32, actual: u32 },
28
29    #[error("Invalid u8 for bool: {0}")]
30    BoolValue(u8),
31
32    #[error("Not a fixed value, required for decimal with fixed schema: {0:?}")]
33    FixedValue(ValueKind),
34
35    #[error("Not a bytes value, required for decimal with bytes schema: {0:?}")]
36    BytesValue(ValueKind),
37
38    #[error("Not a string value, required for uuid: {0:?}")]
39    GetUuidFromStringValue(ValueKind),
40
41    #[error("Two schemas with the same fullname were given: {0:?}")]
42    NameCollision(String),
43
44    #[error("Not a fixed or bytes type, required for decimal schema, got: {0:?}")]
45    ResolveDecimalSchema(SchemaKind),
46
47    #[error("Invalid utf-8 string")]
48    ConvertToUtf8(#[source] std::string::FromUtf8Error),
49
50    #[error("Invalid utf-8 string")]
51    ConvertToUtf8Error(#[source] std::str::Utf8Error),
52
53    /// Describes errors happened while validating Avro data.
54    #[error("Value does not match schema")]
55    Validation,
56
57    /// Describes errors happened while validating Avro data.
58    #[error("Value {value:?} does not match schema {schema:?}: Reason: {reason}")]
59    ValidationWithReason {
60        value: Value,
61        schema: Schema,
62        reason: String,
63    },
64
65    #[error("Unable to allocate {desired} bytes (maximum allowed: {maximum})")]
66    MemoryAllocation { desired: usize, maximum: usize },
67
68    /// Describe a specific error happening with decimal representation
69    #[error("Number of bytes requested for decimal sign extension {requested} is less than the number of bytes needed to decode {needed}")]
70    SignExtend { requested: usize, needed: usize },
71
72    #[error("Failed to read boolean bytes")]
73    ReadBoolean(#[source] std::io::Error),
74
75    #[error("Failed to read bytes")]
76    ReadBytes(#[source] std::io::Error),
77
78    #[error("Failed to read string")]
79    ReadString(#[source] std::io::Error),
80
81    #[error("Failed to read double")]
82    ReadDouble(#[source] std::io::Error),
83
84    #[error("Failed to read float")]
85    ReadFloat(#[source] std::io::Error),
86
87    #[error("Failed to read duration")]
88    ReadDuration(#[source] std::io::Error),
89
90    #[error("Failed to read fixed number of bytes: {1}")]
91    ReadFixed(#[source] std::io::Error, usize),
92
93    #[error("Failed to convert &str to UUID")]
94    ConvertStrToUuid(#[source] uuid::Error),
95
96    #[error("Failed to convert Fixed bytes to UUID. It must be exactly 16 bytes, got {0}")]
97    ConvertFixedToUuid(usize),
98
99    #[error("Failed to convert Fixed bytes to UUID")]
100    ConvertSliceToUuid(#[source] uuid::Error),
101
102    #[error("Map key is not a string; key type is {0:?}")]
103    MapKeyType(ValueKind),
104
105    #[error("Union index {index} out of bounds: {num_variants}")]
106    GetUnionVariant { index: i64, num_variants: usize },
107
108    #[error("Enum symbol index out of bounds: {num_variants}")]
109    EnumSymbolIndex { index: usize, num_variants: usize },
110
111    #[error("Enum symbol not found {0}")]
112    GetEnumSymbol(String),
113
114    #[error("Unable to decode enum index")]
115    GetEnumUnknownIndexValue,
116
117    #[error("Scale {scale} is greater than precision {precision}")]
118    GetScaleAndPrecision { scale: usize, precision: usize },
119
120    #[error(
121        "Fixed type number of bytes {size} is not large enough to hold decimal values of precision {precision}"
122    )]
123    GetScaleWithFixedSize { size: usize, precision: usize },
124
125    #[error("expected UUID, got: {0:?}")]
126    GetUuid(ValueKind),
127
128    #[error("expected BigDecimal, got: {0:?}")]
129    GetBigdecimal(ValueKind),
130
131    #[error("Fixed bytes of size 12 expected, got Fixed of size {0}")]
132    GetDecimalFixedBytes(usize),
133
134    #[error("Duration expected, got {0:?}")]
135    ResolveDuration(ValueKind),
136
137    #[error("Decimal expected, got {0:?}")]
138    ResolveDecimal(ValueKind),
139
140    #[error("Missing field in record: {0:?}")]
141    GetField(String),
142
143    #[error("Unable to convert to u8, got {0:?}")]
144    GetU8(ValueKind),
145
146    #[error("Precision {precision} too small to hold decimal values with {num_bytes} bytes")]
147    ComparePrecisionAndSize { precision: usize, num_bytes: usize },
148
149    #[error("Cannot convert length to i32: {1}")]
150    ConvertLengthToI32(#[source] std::num::TryFromIntError, usize),
151
152    #[error("Date expected, got {0:?}")]
153    GetDate(ValueKind),
154
155    #[error("TimeMillis expected, got {0:?}")]
156    GetTimeMillis(ValueKind),
157
158    #[error("TimeMicros expected, got {0:?}")]
159    GetTimeMicros(ValueKind),
160
161    #[error("TimestampMillis expected, got {0:?}")]
162    GetTimestampMillis(ValueKind),
163
164    #[error("TimestampMicros expected, got {0:?}")]
165    GetTimestampMicros(ValueKind),
166
167    #[error("TimestampNanos expected, got {0:?}")]
168    GetTimestampNanos(ValueKind),
169
170    #[error("LocalTimestampMillis expected, got {0:?}")]
171    GetLocalTimestampMillis(ValueKind),
172
173    #[error("LocalTimestampMicros expected, got {0:?}")]
174    GetLocalTimestampMicros(ValueKind),
175
176    #[error("LocalTimestampNanos expected, got {0:?}")]
177    GetLocalTimestampNanos(ValueKind),
178
179    #[error("Null expected, got {0:?}")]
180    GetNull(ValueKind),
181
182    #[error("Boolean expected, got {0:?}")]
183    GetBoolean(ValueKind),
184
185    #[error("Int expected, got {0:?}")]
186    GetInt(ValueKind),
187
188    #[error("Long expected, got {0:?}")]
189    GetLong(ValueKind),
190
191    #[error("Double expected, got {0:?}")]
192    GetDouble(ValueKind),
193
194    #[error("Float expected, got {0:?}")]
195    GetFloat(ValueKind),
196
197    #[error("Bytes expected, got {0:?}")]
198    GetBytes(ValueKind),
199
200    #[error("String expected, got {0:?}")]
201    GetString(ValueKind),
202
203    #[error("Enum expected, got {0:?}")]
204    GetEnum(ValueKind),
205
206    #[error("Fixed size mismatch, {size} expected, got {n}")]
207    CompareFixedSizes { size: usize, n: usize },
208
209    #[error("String expected for fixed, got {0:?}")]
210    GetStringForFixed(ValueKind),
211
212    #[error("Enum default {symbol:?} is not among allowed symbols {symbols:?}")]
213    GetEnumDefault {
214        symbol: String,
215        symbols: Vec<String>,
216    },
217
218    #[error("Enum value index {index} is out of bounds {nsymbols}")]
219    GetEnumValue { index: usize, nsymbols: usize },
220
221    #[error("Key {0} not found in decimal metadata JSON")]
222    GetDecimalMetadataFromJson(&'static str),
223
224    #[error("Could not find matching type in union")]
225    FindUnionVariant,
226
227    #[error("Union type should not be empty")]
228    EmptyUnion,
229
230    #[error("Array({expected:?}) expected, got {other:?}")]
231    GetArray {
232        expected: SchemaKind,
233        other: ValueKind,
234    },
235
236    #[error("Map({expected:?}) expected, got {other:?}")]
237    GetMap {
238        expected: SchemaKind,
239        other: ValueKind,
240    },
241
242    #[error("Record with fields {expected:?} expected, got {other:?}")]
243    GetRecord {
244        expected: Vec<(String, SchemaKind)>,
245        other: ValueKind,
246    },
247
248    #[error("No `name` field")]
249    GetNameField,
250
251    #[error("No `name` in record field")]
252    GetNameFieldFromRecord,
253
254    #[error("Unions may not directly contain a union")]
255    GetNestedUnion,
256
257    #[error("Unions cannot contain duplicate types")]
258    GetUnionDuplicate,
259
260    #[error("One union type {0:?} must match the `default`'s value type {1:?}")]
261    GetDefaultUnion(SchemaKind, ValueKind),
262
263    #[error("`default`'s value type of field {0:?} in {1:?} must be {2:?}")]
264    GetDefaultRecordField(String, String, String),
265
266    #[error("JSON value {0} claims to be u64 but cannot be converted")]
267    GetU64FromJson(serde_json::Number),
268
269    #[error("JSON value {0} claims to be i64 but cannot be converted")]
270    GetI64FromJson(serde_json::Number),
271
272    #[error("Cannot convert u64 to usize: {1}")]
273    ConvertU64ToUsize(#[source] std::num::TryFromIntError, u64),
274
275    #[error("Cannot convert u32 to usize: {1}")]
276    ConvertU32ToUsize(#[source] std::num::TryFromIntError, u32),
277
278    #[error("Cannot convert i64 to usize: {1}")]
279    ConvertI64ToUsize(#[source] std::num::TryFromIntError, i64),
280
281    #[error("Cannot convert i32 to usize: {1}")]
282    ConvertI32ToUsize(#[source] std::num::TryFromIntError, i32),
283
284    #[error("Invalid JSON value for decimal precision/scale integer: {0}")]
285    GetPrecisionOrScaleFromJson(serde_json::Number),
286
287    #[error("Failed to parse schema from JSON")]
288    ParseSchemaJson(#[source] serde_json::Error),
289
290    #[error("Failed to read schema")]
291    ReadSchemaFromReader(#[source] std::io::Error),
292
293    #[error("Must be a JSON string, object or array")]
294    ParseSchemaFromValidJson,
295
296    #[error("Unknown primitive type: {0}")]
297    ParsePrimitive(String),
298
299    #[error("invalid JSON for {key:?}: {value:?}")]
300    GetDecimalMetadataValueFromJson {
301        key: String,
302        value: serde_json::Value,
303    },
304
305    #[error("The decimal precision ({precision}) must be bigger or equal to the scale ({scale})")]
306    DecimalPrecisionLessThanScale { precision: usize, scale: usize },
307
308    #[error("The decimal precision ({precision}) must be a positive number")]
309    DecimalPrecisionMuBePositive { precision: usize },
310
311    #[error("Unreadable big decimal sign")]
312    BigDecimalSign,
313
314    #[error("Unreadable length for big decimal inner bytes: {0}")]
315    BigDecimalLen(#[source] Box<Error>),
316
317    #[error("Unreadable big decimal scale")]
318    BigDecimalScale,
319
320    #[error("Unexpected `type` {0} variant for `logicalType`")]
321    GetLogicalTypeVariant(serde_json::Value),
322
323    #[error("No `type` field found for `logicalType`")]
324    GetLogicalTypeField,
325
326    #[error("logicalType must be a string, but is {0:?}")]
327    GetLogicalTypeFieldType(serde_json::Value),
328
329    #[error("Unknown complex type: {0}")]
330    GetComplexType(serde_json::Value),
331
332    #[error("No `type` in complex type")]
333    GetComplexTypeField,
334
335    #[error("No `fields` in record")]
336    GetRecordFieldsJson,
337
338    #[error("No `symbols` field in enum")]
339    GetEnumSymbolsField,
340
341    #[error("Unable to parse `symbols` in enum")]
342    GetEnumSymbols,
343
344    #[error("Invalid enum symbol name {0}")]
345    EnumSymbolName(String),
346
347    #[error("Invalid field name {0}")]
348    FieldName(String),
349
350    #[error("Duplicate field name {0}")]
351    FieldNameDuplicate(String),
352
353    #[error("Invalid schema name {0}. It must match the regex '{1}'")]
354    InvalidSchemaName(String, &'static str),
355
356    #[error("Invalid namespace {0}. It must match the regex '{1}'")]
357    InvalidNamespace(String, &'static str),
358
359    #[error("Duplicate enum symbol {0}")]
360    EnumSymbolDuplicate(String),
361
362    #[error("Default value for enum must be a string! Got: {0}")]
363    EnumDefaultWrongType(serde_json::Value),
364
365    #[error("No `items` in array")]
366    GetArrayItemsField,
367
368    #[error("No `values` in map")]
369    GetMapValuesField,
370
371    #[error("Fixed schema `size` value must be a positive integer: {0}")]
372    GetFixedSizeFieldPositive(serde_json::Value),
373
374    #[error("Fixed schema has no `size`")]
375    GetFixedSizeField,
376
377    #[error("Fixed schema's default value length ({0}) does not match its size ({1})")]
378    FixedDefaultLenSizeMismatch(usize, u64),
379
380    #[error("Failed to compress with flate")]
381    DeflateCompress(#[source] std::io::Error),
382
383    #[error("Failed to finish flate compressor")]
384    DeflateCompressFinish(#[source] std::io::Error),
385
386    #[error("Failed to decompress with flate")]
387    DeflateDecompress(#[source] std::io::Error),
388
389    #[cfg(feature = "snappy")]
390    #[error("Failed to compress with snappy")]
391    SnappyCompress(#[source] snap::Error),
392
393    #[cfg(feature = "snappy")]
394    #[error("Failed to get snappy decompression length")]
395    GetSnappyDecompressLen(#[source] snap::Error),
396
397    #[cfg(feature = "snappy")]
398    #[error("Failed to decompress with snappy")]
399    SnappyDecompress(#[source] snap::Error),
400
401    #[error("Failed to compress with zstd")]
402    ZstdCompress(#[source] std::io::Error),
403
404    #[error("Failed to decompress with zstd")]
405    ZstdDecompress(#[source] std::io::Error),
406
407    #[error("Failed to read header")]
408    ReadHeader(#[source] std::io::Error),
409
410    #[error("wrong magic in header")]
411    HeaderMagic,
412
413    #[error("Message Header mismatch. Expected: {0:?}. Actual: {1:?}")]
414    SingleObjectHeaderMismatch([u8; 10], [u8; 10]),
415
416    #[error("Failed to get JSON from avro.schema key in map")]
417    GetAvroSchemaFromMap,
418
419    #[error("no metadata in header")]
420    GetHeaderMetadata,
421
422    #[error("Failed to read marker bytes")]
423    ReadMarker(#[source] std::io::Error),
424
425    #[error("Failed to read block marker bytes")]
426    ReadBlockMarker(#[source] std::io::Error),
427
428    #[error("Read into buffer failed")]
429    ReadIntoBuf(#[source] std::io::Error),
430
431    #[error("block marker does not match header marker")]
432    GetBlockMarker,
433
434    #[error("Overflow when decoding integer value")]
435    IntegerOverflow,
436
437    #[error("Failed to read bytes for decoding variable length integer")]
438    ReadVariableIntegerBytes(#[source] std::io::Error),
439
440    #[error("Decoded integer out of range for i32: {1}")]
441    ZagI32(#[source] std::num::TryFromIntError, i64),
442
443    #[error("unable to read block")]
444    ReadBlock,
445
446    #[error("Failed to serialize value into Avro value: {0}")]
447    SerializeValue(String),
448
449    #[error("Failed to deserialize Avro value into value: {0}")]
450    DeserializeValue(String),
451
452    #[error("Failed to write buffer bytes during flush")]
453    WriteBytes(#[source] std::io::Error),
454
455    #[error("Failed to write marker")]
456    WriteMarker(#[source] std::io::Error),
457
458    #[error("Failed to convert JSON to string")]
459    ConvertJsonToString(#[source] serde_json::Error),
460
461    /// Error while converting float to json value
462    #[error("failed to convert avro float to json: {0}")]
463    ConvertF64ToJson(f64),
464
465    /// Error while resolving Schema::Ref
466    #[error("Unresolved schema reference: {0}")]
467    SchemaResolutionError(Name),
468
469    #[error("The file metadata is already flushed.")]
470    FileHeaderAlreadyWritten,
471
472    #[error("Metadata keys starting with 'avro.' are reserved for internal usage: {0}.")]
473    InvalidMetadataKey(String),
474
475    /// Error when two named schema have the same fully qualified name
476    #[error("Two named schema defined for same fullname: {0}.")]
477    AmbiguousSchemaDefinition(Name),
478
479    #[error("Signed decimal bytes length {0} not equal to fixed schema size {1}.")]
480    EncodeDecimalAsFixedError(usize, usize),
481
482    #[error("There is no entry for '{0}' in the lookup table: {1}.")]
483    NoEntryInLookupTable(String, String),
484
485    #[error("Can only encode value type {value_kind:?} as one of {supported_schema:?}")]
486    EncodeValueAsSchemaError {
487        value_kind: ValueKind,
488        supported_schema: Vec<SchemaKind>,
489    },
490    #[error(
491        "Internal buffer not drained properly. Re-initialize the single object writer struct!"
492    )]
493    IllegalSingleObjectWriterState,
494
495    #[error("Codec '{0}' is not supported/enabled")]
496    CodecNotSupported(String),
497
498    #[error("Invalid Avro data! Cannot read codec type from value that is not Value::Bytes.")]
499    BadCodecMetadata,
500}
501
502#[derive(thiserror::Error, PartialEq)]
503pub enum CompatibilityError {
504    #[error("Incompatible schema types! Writer schema is '{writer_schema_type}', but reader schema is '{reader_schema_type}'")]
505    WrongType {
506        writer_schema_type: String,
507        reader_schema_type: String,
508    },
509
510    #[error("Incompatible schema types! The {schema_type} should have been {expected_type:?}")]
511    TypeExpected {
512        schema_type: String,
513        expected_type: Vec<SchemaKind>,
514    },
515
516    #[error("Incompatible schemata! Field '{0}' in reader schema does not match the type in the writer schema")]
517    FieldTypeMismatch(String, #[source] Box<CompatibilityError>),
518
519    #[error("Incompatible schemata! Field '{0}' in reader schema must have a default value")]
520    MissingDefaultValue(String),
521
522    #[error("Incompatible schemata! Reader's symbols must contain all writer's symbols")]
523    MissingSymbols,
524
525    #[error("Incompatible schemata! All elements in union must match for both schemas")]
526    MissingUnionElements,
527
528    #[error("Incompatible schemata! Name and size don't match for fixed")]
529    FixedMismatch,
530
531    #[error("Incompatible schemata! The name must be the same for both schemas. Writer's name {writer_name} and reader's name {reader_name}")]
532    NameMismatch {
533        writer_name: String,
534        reader_name: String,
535    },
536
537    #[error(
538        "Incompatible schemata! Unknown type for '{0}'. Make sure that the type is a valid one"
539    )]
540    Inconclusive(String),
541}
542
543impl serde::ser::Error for Error {
544    fn custom<T: fmt::Display>(msg: T) -> Self {
545        Error::SerializeValue(msg.to_string())
546    }
547}
548
549impl serde::de::Error for Error {
550    fn custom<T: fmt::Display>(msg: T) -> Self {
551        Error::DeserializeValue(msg.to_string())
552    }
553}
554
555impl fmt::Debug for Error {
556    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
557        let mut msg = self.to_string();
558        if let Some(e) = self.source() {
559            msg.extend([": ", &e.to_string()]);
560        }
561        write!(f, "{}", msg)
562    }
563}
564
565impl fmt::Debug for CompatibilityError {
566    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
567        let mut msg = self.to_string();
568        if let Some(e) = self.source() {
569            msg.extend([": ", &e.to_string()]);
570        }
571        write!(f, "{}", msg)
572    }
573}