Skip to main content

scylla_cql/frame/
frame_errors.rs

1//! Low-level errors that can occur during CQL frame parsing and serialization.
2
3use std::error::Error;
4use std::sync::Arc;
5
6pub use super::request::{
7    auth_response::AuthResponseSerializationError,
8    batch::{BatchSerializationError, BatchStatementSerializationError},
9    execute::ExecuteSerializationError,
10    prepare::PrepareSerializationError,
11    query::{QueryParametersSerializationError, QuerySerializationError},
12    register::RegisterSerializationError,
13    startup::StartupSerializationError,
14};
15
16use super::TryFromPrimitiveError;
17use super::response::CqlResponseKind;
18use crate::utils::parse::ParseErrorCause;
19use thiserror::Error;
20
21/// An error returned by `parse_response_body_extensions`.
22///
23/// It represents an error that occurred during deserialization of
24/// frame body extensions. These extensions include tracing id,
25/// warnings and custom payload.
26///
27/// Possible error kinds:
28/// - failed to decompress frame body (decompression is required for further deserialization)
29/// - failed to deserialize tracing id (body ext.)
30/// - failed to deserialize warnings list (body ext.)
31/// - failed to deserialize custom payload map (body ext.)
32#[derive(Error, Debug, Clone)]
33#[non_exhaustive]
34pub enum FrameBodyExtensionsParseError {
35    /// Frame is compressed, but no compression was negotiated for the connection.
36    #[error("Frame is compressed, but no compression negotiated for connection.")]
37    NoCompressionNegotiated,
38
39    /// Failed to deserialize frame trace id.
40    #[error("Malformed trace id: {0}")]
41    TraceIdParse(LowLevelDeserializationError),
42
43    /// Failed to deserialize warnings attached to frame.
44    #[error("Malformed warnings list: {0}")]
45    WarningsListParse(LowLevelDeserializationError),
46
47    /// Failed to deserialize frame's custom payload.
48    #[error("Malformed custom payload map: {0}")]
49    CustomPayloadMapParse(LowLevelDeserializationError),
50
51    /// Failed to decompress frame body (snap).
52    #[error("Snap decompression error: {0}")]
53    SnapDecompressError(Arc<dyn Error + Sync + Send>),
54
55    /// Failed to decompress frame body (lz4).
56    #[error("Error decompressing lz4 data {0}")]
57    Lz4DecompressError(Arc<dyn Error + Sync + Send>),
58}
59
60/// An error that occurred during frame header deserialization.
61#[derive(Debug, Error)]
62#[non_exhaustive]
63pub enum FrameHeaderParseError {
64    /// Failed to read the frame header from the socket.
65    #[error("Failed to read the frame header: {0}")]
66    HeaderIoError(std::io::Error),
67
68    /// Received a frame marked as coming from a client.
69    #[error("Received frame marked as coming from a client")]
70    FrameFromClient,
71
72    /// Received a frame marked as coming from a server, while expecting a frame
73    /// coming from a client.
74    // FIXME: this should not belong here. User always expects a frame from server.
75    // This variant is only used in scylla-proxy - need to investigate it later.
76    #[error("Received frame marked as coming from the server")]
77    FrameFromServer,
78
79    /// Received a frame with unsupported version.
80    #[error("Received a frame from version {0}, but only 4 is supported")]
81    VersionNotSupported(u8),
82
83    /// Received unknown response opcode.
84    #[error("Unrecognized response opcode {0}")]
85    UnknownResponseOpcode(#[from] TryFromPrimitiveError<u8>),
86
87    /// Failed to read frame body from the socket.
88    #[error("Failed to read a chunk of response body. Expected {0} more bytes, error: {1}")]
89    BodyChunkIoError(usize, std::io::Error),
90
91    /// Connection was closed before whole frame was read.
92    #[error("Connection was closed before body was read: missing {0} out of {1}")]
93    ConnectionClosed(usize, usize),
94}
95
96/// An error that occurred during CQL request serialization.
97#[non_exhaustive]
98#[derive(Error, Debug, Clone)]
99pub enum CqlRequestSerializationError {
100    /// Failed to serialize STARTUP request.
101    #[error("Failed to serialize STARTUP request: {0}")]
102    StartupSerialization(#[from] StartupSerializationError),
103
104    /// Failed to serialize REGISTER request.
105    #[error("Failed to serialize REGISTER request: {0}")]
106    RegisterSerialization(#[from] RegisterSerializationError),
107
108    /// Failed to serialize AUTH_RESPONSE request.
109    #[error("Failed to serialize AUTH_RESPONSE request: {0}")]
110    AuthResponseSerialization(#[from] AuthResponseSerializationError),
111
112    /// Failed to serialize BATCH request.
113    #[error("Failed to serialize BATCH request: {0}")]
114    BatchSerialization(#[from] BatchSerializationError),
115
116    /// Failed to serialize PREPARE request.
117    #[error("Failed to serialize PREPARE request: {0}")]
118    PrepareSerialization(#[from] PrepareSerializationError),
119
120    /// Failed to serialize EXECUTE request.
121    #[error("Failed to serialize EXECUTE request: {0}")]
122    ExecuteSerialization(#[from] ExecuteSerializationError),
123
124    /// Failed to serialize QUERY request.
125    #[error("Failed to serialize QUERY request: {0}")]
126    QuerySerialization(#[from] QuerySerializationError),
127
128    /// Request body compression failed.
129    #[error("Snap compression error: {0}")]
130    SnapCompressError(Arc<dyn Error + Sync + Send>),
131}
132
133/// An error type returned when deserialization of CQL
134/// server response fails.
135#[non_exhaustive]
136#[derive(Error, Debug, Clone)]
137// Check triggers because all variants begin with "Cql".
138// TODO(2.0): Remove the "Cql" prefix from variants.
139#[expect(clippy::enum_variant_names)]
140pub enum CqlResponseParseError {
141    #[error("Failed to deserialize ERROR response: {0}")]
142    CqlErrorParseError(#[from] CqlErrorParseError),
143    #[error("Failed to deserialize AUTH_CHALLENGE response: {0}")]
144    CqlAuthChallengeParseError(#[from] CqlAuthChallengeParseError),
145    #[error("Failed to deserialize AUTH_SUCCESS response: {0}")]
146    CqlAuthSuccessParseError(#[from] CqlAuthSuccessParseError),
147    #[error("Failed to deserialize AUTHENTICATE response: {0}")]
148    CqlAuthenticateParseError(#[from] CqlAuthenticateParseError),
149    #[error("Failed to deserialize SUPPORTED response: {0}")]
150    CqlSupportedParseError(#[from] CqlSupportedParseError),
151    #[error("Failed to deserialize EVENT response: {0}")]
152    CqlEventParseError(#[from] CqlEventParseError),
153    #[error(transparent)]
154    CqlResultParseError(#[from] CqlResultParseError),
155}
156
157impl CqlResponseParseError {
158    /// Retrieves the kind of CQL response that this error corresponds to.
159    pub fn to_response_kind(&self) -> CqlResponseKind {
160        match self {
161            CqlResponseParseError::CqlErrorParseError(_) => CqlResponseKind::Error,
162            CqlResponseParseError::CqlAuthChallengeParseError(_) => CqlResponseKind::AuthChallenge,
163            CqlResponseParseError::CqlAuthSuccessParseError(_) => CqlResponseKind::AuthSuccess,
164            CqlResponseParseError::CqlAuthenticateParseError(_) => CqlResponseKind::Authenticate,
165            CqlResponseParseError::CqlSupportedParseError(_) => CqlResponseKind::Supported,
166            CqlResponseParseError::CqlEventParseError(_) => CqlResponseKind::Event,
167            CqlResponseParseError::CqlResultParseError(_) => CqlResponseKind::Result,
168        }
169    }
170}
171
172/// An error type returned when deserialization of ERROR response fails.
173#[non_exhaustive]
174#[derive(Error, Debug, Clone)]
175pub enum CqlErrorParseError {
176    #[error("Malformed error code: {0}")]
177    ErrorCodeParseError(LowLevelDeserializationError),
178    #[error("Malformed error reason: {0}")]
179    ReasonParseError(LowLevelDeserializationError),
180    #[error("Malformed error field {field} of DB error {db_error}: {err}")]
181    MalformedErrorField {
182        db_error: &'static str,
183        field: &'static str,
184        err: LowLevelDeserializationError,
185    },
186}
187
188/// An error type returned when deserialization of AUTH_CHALLENGE response fails.
189#[non_exhaustive]
190#[derive(Error, Debug, Clone)]
191pub enum CqlAuthChallengeParseError {
192    #[error("Malformed authenticate message: {0}")]
193    AuthMessageParseError(LowLevelDeserializationError),
194}
195
196/// An error type returned when deserialization of AUTH_SUCCESS response fails.
197#[non_exhaustive]
198#[derive(Error, Debug, Clone)]
199pub enum CqlAuthSuccessParseError {
200    #[error("Malformed success message: {0}")]
201    SuccessMessageParseError(LowLevelDeserializationError),
202}
203
204/// An error type returned when deserialization of AUTHENTICATE response fails.
205#[non_exhaustive]
206#[derive(Error, Debug, Clone)]
207pub enum CqlAuthenticateParseError {
208    #[error("Malformed authenticator name: {0}")]
209    AuthNameParseError(LowLevelDeserializationError),
210}
211
212/// An error type returned when deserialization of SUPPORTED response fails.
213#[non_exhaustive]
214#[derive(Error, Debug, Clone)]
215pub enum CqlSupportedParseError {
216    #[error("Malformed options map: {0}")]
217    OptionsMapDeserialization(LowLevelDeserializationError),
218}
219
220/// An error type returned when deserialization of RESULT response fails.
221#[non_exhaustive]
222#[derive(Error, Debug, Clone)]
223pub enum CqlResultParseError {
224    #[error("Malformed RESULT response id: {0}")]
225    ResultIdParseError(LowLevelDeserializationError),
226    #[error("Unknown RESULT response id: {0}")]
227    UnknownResultId(i32),
228    #[error("RESULT:Set_keyspace response deserialization failed: {0}")]
229    SetKeyspaceParseError(#[from] SetKeyspaceParseError),
230    // This is an error returned during deserialization of
231    // `RESULT::Schema_change` response, and not `EVENT` response.
232    #[error("RESULT:Schema_change response deserialization failed: {0}")]
233    SchemaChangeParseError(#[from] SchemaChangeEventParseError),
234    #[error("RESULT:Prepared response deserialization failed: {0}")]
235    PreparedParseError(#[from] PreparedParseError),
236    #[error("RESULT:Rows response deserialization failed: {0}")]
237    RawRowsParseError(#[from] RawRowsAndPagingStateResponseParseError),
238    #[error("RESULT:Rows result metadata response deserialization failed: {0}")]
239    ResultMetadataParseError(#[from] ResultMetadataAndRowsCountParseError),
240}
241
242#[non_exhaustive]
243#[derive(Error, Debug, Clone)]
244pub enum SetKeyspaceParseError {
245    #[error("Malformed keyspace name: {0}")]
246    MalformedKeyspaceName(#[from] LowLevelDeserializationError),
247}
248
249/// An error type returned when deserialization of
250/// `EVENT` response fails.
251#[non_exhaustive]
252#[derive(Error, Debug, Clone)]
253pub enum CqlEventParseError {
254    #[error("Malformed event type string: {0}")]
255    EventTypeParseError(LowLevelDeserializationError),
256    #[error("Unknown event type: {0}")]
257    UnknownEventType(String),
258    #[error("Failed to deserialize schema change event: {0}")]
259    SchemaChangeEventParseError(#[from] SchemaChangeEventParseError),
260    #[error("Failed to deserialize topology change event: {0}")]
261    TopologyChangeEventParseError(ClusterChangeEventParseError),
262    #[error("Failed to deserialize status change event: {0}")]
263    StatusChangeEventParseError(ClusterChangeEventParseError),
264    #[error("Failed to deserialize client routes change event: {0}")]
265    ClientRoutesChangeEventParseError(ClientRoutesChangeEventParseError),
266}
267
268/// An error type returned when deserialization of
269/// SchemaChangeEvent fails.
270#[non_exhaustive]
271#[derive(Error, Debug, Clone)]
272pub enum SchemaChangeEventParseError {
273    #[error("Malformed schema change type string: {0}")]
274    TypeOfChangeParseError(LowLevelDeserializationError),
275    #[error("Malformed schema change target string:: {0}")]
276    TargetTypeParseError(LowLevelDeserializationError),
277    #[error("Malformed name of keyspace affected by schema change: {0}")]
278    AffectedKeyspaceParseError(LowLevelDeserializationError),
279    #[error("Malformed name of the table affected by schema change: {0}")]
280    AffectedTableNameParseError(LowLevelDeserializationError),
281    #[error("Malformed name of the target affected by schema change: {0}")]
282    AffectedTargetNameParseError(LowLevelDeserializationError),
283    #[error(
284        "Malformed number of arguments of the function/aggregate affected by schema change: {0}"
285    )]
286    ArgumentCountParseError(LowLevelDeserializationError),
287    #[error("Malformed argument of the function/aggregate affected by schema change: {0}")]
288    FunctionArgumentParseError(LowLevelDeserializationError),
289    #[error("Unknown target of schema change: {0}")]
290    UnknownTargetOfSchemaChange(String),
291}
292
293/// An error type returned when deserialization of [Status/Topology]ChangeEvent fails.
294#[non_exhaustive]
295#[derive(Error, Debug, Clone)]
296pub enum ClusterChangeEventParseError {
297    #[error("Malformed type of change: {0}")]
298    TypeOfChangeParseError(LowLevelDeserializationError),
299    #[error("Malformed node address: {0}")]
300    NodeAddressParseError(LowLevelDeserializationError),
301    #[error("Unknown type of change: {0}")]
302    UnknownTypeOfChange(String),
303}
304
305/// An error type returned when deserialization of ClientRoutesChangeEvent fails.
306#[non_exhaustive]
307#[derive(Error, Debug, Clone)]
308pub enum ClientRoutesChangeEventParseError {
309    #[error("Malformed type of change: {0}")]
310    TypeOfChangeParseError(LowLevelDeserializationError),
311    #[error("Unknown type of change: {0}")]
312    UnknownTypeOfChange(String),
313    #[error("Malformed connection ids: {0}")]
314    ConnectionIdsParseError(LowLevelDeserializationError),
315    #[error("Malformed host ids: {0}")]
316    HostIdsParseError(LowLevelDeserializationError),
317    #[error("Unable to parse host id as UUID: {0}")]
318    HostIdsUuidParseError(uuid::Error),
319    #[error(
320        "Connection and host ids length mismatch: there are {connection_ids_count} connection ids and {host_ids_count} host ids"
321    )]
322    ConnectionHostIdsLengthMismatch {
323        connection_ids_count: usize,
324        host_ids_count: usize,
325    },
326}
327
328/// An error type returned when deserialization
329/// of `RESULT::`Prepared` response fails.
330#[non_exhaustive]
331#[derive(Debug, Error, Clone)]
332pub enum PreparedParseError {
333    // TODO(2.0): This variant is unused, and should be removed.
334    #[error("Malformed prepared statement's id length: {0}")]
335    IdLengthParseError(LowLevelDeserializationError),
336    #[error("Malformed prepared statement's id: {0}")]
337    IdParseError(LowLevelDeserializationError),
338    #[error("Malformed prepared statement's result metadata id: {0}")]
339    ResultMetadataIdParseError(LowLevelDeserializationError),
340    #[error("Invalid result metadata: {0}")]
341    ResultMetadataParseError(ResultMetadataParseError),
342    #[error("Invalid prepared metadata: {0}")]
343    PreparedMetadataParseError(PreparedMetadataParseError),
344    #[error("Non-zero paging state in result metadata: {0:?}")]
345    NonZeroPagingState(Arc<[u8]>),
346}
347
348/// An error that occurred during initial deserialization of
349/// `RESULT:Rows` response. Since the deserialization of rows is lazy,
350/// we initially only need to deserialize:
351/// - result metadata flags
352/// - column count (result metadata)
353/// - paging state response
354#[non_exhaustive]
355#[derive(Debug, Error, Clone)]
356// TODO(2.0): Remove the "ParseError" postfix from variants.
357pub enum RawRowsAndPagingStateResponseParseError {
358    /// Failed to parse metadata flags.
359    #[error("Malformed metadata flags: {0}")]
360    FlagsParseError(LowLevelDeserializationError),
361
362    /// Failed to parse column count.
363    #[error("Malformed column count: {0}")]
364    ColumnCountParseError(LowLevelDeserializationError),
365
366    /// Failed to parse paging state response.
367    #[error("Malformed paging state: {0}")]
368    PagingStateParseError(LowLevelDeserializationError),
369
370    #[error("Metadata_changed and No_metadata flags are both present")]
371    IdPresentForEmptyMetadata,
372}
373
374/// An error type returned when deserialization
375/// of statement's prepared metadata failed.
376#[non_exhaustive]
377#[derive(Error, Debug, Clone)]
378// Check triggers because all variants end with "ParseError".
379// TODO(2.0): Remove the "ParseError" postfix from variants.
380#[expect(clippy::enum_variant_names)]
381pub enum PreparedMetadataParseError {
382    /// Failed to parse metadata flags.
383    #[error("Malformed metadata flags: {0}")]
384    FlagsParseError(LowLevelDeserializationError),
385
386    /// Failed to parse column count.
387    #[error("Malformed column count: {0}")]
388    ColumnCountParseError(LowLevelDeserializationError),
389
390    /// Failed to parse partition key count.
391    #[error("Malformed partition key count: {0}")]
392    PkCountParseError(LowLevelDeserializationError),
393
394    /// Failed to parse partition key index.
395    #[error("Malformed partition key index: {0}")]
396    PkIndexParseError(LowLevelDeserializationError),
397
398    /// Failed to parse global table spec.
399    #[error("Invalid global table spec: {0}")]
400    GlobalTableSpecParseError(#[from] TableSpecParseError),
401
402    /// Failed to parse column spec.
403    #[error("Invalid column spec: {0}")]
404    ColumnSpecParseError(#[from] ColumnSpecParseError),
405}
406
407/// An error returned when lazy deserialization of
408/// result metadata and rows count fails.
409#[non_exhaustive]
410#[derive(Error, Debug, Clone)]
411pub enum ResultMetadataAndRowsCountParseError {
412    /// Failed to deserialize result metadata.
413    #[error("Failed to lazily deserialize result metadata: {0}")]
414    ResultMetadataParseError(#[from] ResultMetadataParseError),
415
416    /// Received malformed rows count from the server.
417    #[error("Malformed rows count: {0}")]
418    RowsCountParseError(LowLevelDeserializationError),
419}
420
421/// An error type returned when deserialization
422/// of result metadata failed.
423#[non_exhaustive]
424#[derive(Error, Debug, Clone)]
425// TODO(2.0): Remove the "ParseError" postfix from variants.
426pub enum ResultMetadataParseError {
427    /// Failed to parse metadata flags.
428    #[error("Malformed metadata flags: {0}")]
429    FlagsParseError(LowLevelDeserializationError),
430
431    /// Failed to parse column count.
432    #[error("Malformed column count: {0}")]
433    ColumnCountParseError(LowLevelDeserializationError),
434
435    /// Failed to parse paging state response.
436    #[error("Malformed paging state: {0}")]
437    PagingStateParseError(LowLevelDeserializationError),
438
439    /// Failed to parse new metadata id
440    #[error("Malformed new metadata id: {0}")]
441    NewMetadataIdParseError(LowLevelDeserializationError),
442
443    /// Failed to parse global table spec.
444    #[error("Invalid global table spec: {0}")]
445    GlobalTableSpecParseError(#[from] TableSpecParseError),
446
447    /// Failed to parse column spec.
448    #[error("Invalid column spec: {0}")]
449    ColumnSpecParseError(#[from] ColumnSpecParseError),
450
451    #[error("Metadata_changed and No_metadata flags are both present")]
452    IdPresentForEmptyMetadata,
453}
454
455/// An error type returned when deserialization
456/// of table specification fails.
457#[non_exhaustive]
458#[derive(Error, Debug, Clone)]
459pub enum TableSpecParseError {
460    #[error("Malformed keyspace name: {0}")]
461    MalformedKeyspaceName(LowLevelDeserializationError),
462    #[error("Malformed table name: {0}")]
463    MalformedTableName(LowLevelDeserializationError),
464}
465
466/// An error type returned when deserialization
467/// of table column specifications fails.
468#[non_exhaustive]
469#[derive(Error, Debug, Clone)]
470#[error("Column spec deserialization failed, column index: {column_index}, error: {kind}")]
471pub struct ColumnSpecParseError {
472    pub column_index: usize,
473    pub kind: ColumnSpecParseErrorKind,
474}
475
476/// The type of error that appeared during deserialization
477/// of a column specification.
478#[non_exhaustive]
479#[derive(Error, Debug, Clone)]
480// Check triggers because all variants end with "ParseError".
481// TODO(2.0): Remove the "ParseError" postfix from variants.
482#[expect(clippy::enum_variant_names)]
483pub enum ColumnSpecParseErrorKind {
484    #[error("Invalid table spec: {0}")]
485    TableSpecParseError(#[from] TableSpecParseError),
486    #[error("Malformed column name: {0}")]
487    ColumnNameParseError(#[from] LowLevelDeserializationError),
488    #[error("Invalid column type: {0}")]
489    ColumnTypeParseError(#[from] CqlTypeParseError),
490}
491
492/// An error type returned when deserialization of Custom CQL type name fails.
493#[non_exhaustive]
494#[derive(Error, Debug, Clone, PartialEq, Eq)]
495pub enum CustomTypeParseError {
496    #[error("Malformed simple custom type name: {0}")]
497    UnknownSimpleCustomTypeName(String),
498    #[error("Malformed complex custom type name: {0}")]
499    UnknownComplexCustomTypeName(String),
500    #[error("Unexpected character encountered: {0}, expected: {1}")]
501    UnexpectedCharacter(char, char),
502    #[error("Unable to parse an integer: {0}")]
503    IntegerParseError(ParseErrorCause),
504    #[error("Unexpected end of input")]
505    UnexpectedEndOfInput,
506    #[error("Bad hex string: {0}")]
507    BadHexString(String),
508    #[error("Bytes {0:?} do not represent a valid UTF-8 string")]
509    InvalidUtf8(Vec<u8>),
510    #[error("Wrong number of parameters {actual}, expected: {expected}")]
511    InvalidParameterCount { actual: usize, expected: usize },
512}
513
514/// An error type returned when deserialization of CQL type name fails.
515#[non_exhaustive]
516#[derive(Error, Debug, Clone)]
517pub enum CqlTypeParseError {
518    #[error("Malformed type id: {0}")]
519    TypeIdParseError(LowLevelDeserializationError),
520    #[error("Malformed custom type name: {0}")]
521    CustomTypeNameParseError(LowLevelDeserializationError),
522    #[error("Unsupported custom type: {0}")]
523    CustomTypeUnsupported(String),
524    #[error("Malformed name of UDT keyspace: {0}")]
525    UdtKeyspaceNameParseError(LowLevelDeserializationError),
526    #[error("Malformed UDT name: {0}")]
527    UdtNameParseError(LowLevelDeserializationError),
528    #[error("Malformed UDT fields count: {0}")]
529    UdtFieldsCountParseError(LowLevelDeserializationError),
530    #[error("Malformed UDT's field name: {0}")]
531    UdtFieldNameParseError(LowLevelDeserializationError),
532    #[error("Malformed tuple length: {0}")]
533    TupleLengthParseError(LowLevelDeserializationError),
534    #[error("CQL Type not yet implemented, id: {0}")]
535    TypeNotImplemented(u16),
536    #[error("Failed to parse custom CQL type: {0}")]
537    CustomTypeParseError(CustomTypeParseError),
538}
539
540/// A low level deserialization error.
541///
542/// This type of error is returned when deserialization
543/// of some primitive value fails.
544///
545/// Possible error kinds:
546/// - generic io error - reading from buffer failed
547/// - out of range integer conversion
548/// - conversion errors - e.g. slice-to-array or primitive-to-enum
549/// - not enough bytes in the buffer to deserialize a value
550#[non_exhaustive]
551#[derive(Error, Debug, Clone)]
552pub enum LowLevelDeserializationError {
553    #[error(transparent)]
554    IoError(Arc<std::io::Error>),
555    #[error(transparent)]
556    TryFromIntError(#[from] std::num::TryFromIntError),
557    #[error(transparent)]
558    TryFromSliceError(#[from] std::array::TryFromSliceError),
559    #[error("Not enough bytes! expected: {expected}, received: {received}")]
560    TooFewBytesReceived { expected: usize, received: usize },
561    #[error("Invalid value length: {0}")]
562    InvalidValueLength(i32),
563    #[error("Unknown consistency: {0}")]
564    UnknownConsistency(#[from] TryFromPrimitiveError<u16>),
565    #[error("Invalid inet bytes length: {0}. Accepted lengths are 4 and 16 bytes.")]
566    InvalidInetLength(u8),
567    #[error("UTF8 deserialization failed: {0}")]
568    UTF8DeserializationError(#[from] std::str::Utf8Error),
569}
570
571impl From<std::io::Error> for LowLevelDeserializationError {
572    fn from(value: std::io::Error) -> Self {
573        Self::IoError(Arc::new(value))
574    }
575}