Skip to main content

buffa/
error.rs

1//! Error types for buffa encoding and decoding operations.
2
3/// An error that occurred while decoding a protobuf message.
4#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
5#[non_exhaustive]
6pub enum DecodeError {
7    /// The buffer ended before a complete value could be read.
8    #[error("unexpected end of buffer")]
9    UnexpectedEof,
10
11    /// A varint exceeded the maximum encoded length of 10 bytes.
12    #[error("varint exceeded maximum length of 10 bytes")]
13    VarintTooLong,
14
15    /// The wire type in a tag was not a recognised protobuf wire type.
16    ///
17    /// Carries the raw 3-bit value from the tag for diagnostic purposes.
18    #[error("invalid wire type: {0}")]
19    InvalidWireType(u32),
20
21    /// The field number decoded from a tag was zero, or the tag varint
22    /// overflowed a `u32` — both indicate a malformed message.
23    #[error("invalid field number")]
24    InvalidFieldNumber,
25
26    /// The message or sub-message length exceeded the size limit.
27    ///
28    /// By default, the limit is the 2 GiB protobuf maximum. Use
29    /// [`DecodeOptions::with_max_message_size`](crate::DecodeOptions::with_max_message_size)
30    /// to set a lower limit for untrusted input. Fallible re-encode paths
31    /// ([`OwnedView::from_owned`](crate::view::OwnedView::from_owned)) also
32    /// surface an over-limit *encode* through this variant, mirroring
33    /// [`EncodeError::MessageTooLarge`].
34    #[error("message length exceeds the size limit (2 GiB protobuf maximum, or a configured DecodeOptions limit)")]
35    MessageTooLarge,
36
37    /// The wire type of an incoming field did not match the type expected for
38    /// that field number.
39    ///
40    /// Carries the field number and the raw wire type values (as `u8` to keep
41    /// this type independent of the encoding module).
42    #[error("wire type mismatch on field {field_number}: expected {expected}, got {actual}")]
43    WireTypeMismatch {
44        field_number: u32,
45        expected: u8,
46        actual: u8,
47    },
48
49    /// A `string` field contained bytes that are not valid UTF-8.
50    #[error("invalid UTF-8 in string field")]
51    InvalidUtf8,
52
53    /// The message nesting depth exceeded the recursion limit.
54    #[error("recursion limit exceeded")]
55    RecursionLimitExceeded,
56
57    /// An EndGroup tag was encountered with a field number that does not match
58    /// the opening StartGroup tag, or an EndGroup was seen outside of a group.
59    #[error("invalid end-group tag: field number {0}")]
60    InvalidEndGroup(u32),
61
62    /// A MessageSet `Item` group was malformed (missing or out-of-range
63    /// `type_id`). Only occurs for messages declared with
64    /// `option message_set_wire_format = true`.
65    #[error("invalid MessageSet item: {0}")]
66    InvalidMessageSet(&'static str),
67
68    /// Decoding encountered more unknown fields than the configured limit.
69    ///
70    /// Unknown fields can be far smaller on the wire than in memory (a
71    /// 2-byte varint field occupies ~40 bytes as an
72    /// [`UnknownField`](crate::UnknownField)), so the decoder bounds how
73    /// many it will materialize rather than trusting the input size. By
74    /// default the limit is
75    /// [`DEFAULT_UNKNOWN_FIELD_LIMIT`](crate::DEFAULT_UNKNOWN_FIELD_LIMIT)
76    /// (1,000,000 fields per decode); use
77    /// [`DecodeOptions::with_unknown_field_limit`](crate::DecodeOptions::with_unknown_field_limit)
78    /// to raise it for trusted inputs that legitimately carry very many
79    /// unknown fields.
80    #[error("unknown field limit exceeded")]
81    UnknownFieldLimitExceeded,
82
83    /// A decode would materialize more memory in the elements of
84    /// length-delimited containers — repeated message, string and bytes fields,
85    /// and map entries — than its budget allows.
86    ///
87    /// These elements cost far more decoded than encoded: an empty message
88    /// element is two bytes on the wire and `size_of::<T>()` in the `Vec` it
89    /// lands in, so a payload well inside
90    /// [`DecodeOptions::with_max_message_size`](crate::DecodeOptions::with_max_message_size)
91    /// can still expand by two orders of magnitude. By default the budget is
92    /// [`DEFAULT_ELEMENT_MEMORY_LIMIT`](crate::DEFAULT_ELEMENT_MEMORY_LIMIT)
93    /// (32 MiB per decode); use
94    /// [`DecodeOptions::with_element_memory_limit`](crate::DecodeOptions::with_element_memory_limit)
95    /// to raise it for trusted inputs that legitimately decode into more.
96    #[error("element memory limit exceeded")]
97    ElementMemoryLimitExceeded,
98
99    /// A custom `string`/`bytes` representation rejected the decoded payload in
100    /// its [`from_wire`](crate::ProtoString::from_wire) constructor — for
101    /// example a length or domain check beyond UTF-8 validation. Carries a
102    /// static reason for diagnostics (mirroring [`InvalidMessageSet`]).
103    ///
104    /// Only produced by user-supplied [`ProtoString`](crate::ProtoString) /
105    /// [`ProtoBytes`](crate::ProtoBytes) impls; the built-in representations
106    /// never return it.
107    ///
108    /// [`InvalidMessageSet`]: DecodeError::InvalidMessageSet
109    #[error("custom representation rejected the field value: {0}")]
110    Custom(&'static str),
111}
112
113/// An error that occurred while encoding a protobuf message.
114///
115/// Returned by the `try_encode*` family
116/// ([`Message::try_encode`](crate::Message::try_encode) and friends). The
117/// panicking entry points ([`Message::encode`](crate::Message::encode) and
118/// friends) raise the same conditions as panics instead.
119///
120/// The enum is `#[non_exhaustive]`: further variants may be added without a
121/// breaking change to the type name.
122#[derive(Clone, Debug, PartialEq, Eq, thiserror::Error)]
123#[non_exhaustive]
124pub enum EncodeError {
125    /// The message's encoded size exceeds the 2 GiB protobuf limit
126    /// ([`MAX_MESSAGE_BYTES`](crate::MAX_MESSAGE_BYTES)).
127    ///
128    /// Encoding such a message would produce bytes that no conforming
129    /// protobuf decoder — including buffa's own, which returns the mirror
130    /// error [`DecodeError::MessageTooLarge`] — will accept. Shrink or
131    /// split the message instead.
132    #[error("message encoded size exceeds the 2 GiB protobuf limit")]
133    MessageTooLarge,
134
135    /// The message's encoded size exceeds the caller-supplied budget passed
136    /// to a `try_encode_bounded*` entry point. The message is within the
137    /// 2 GiB protobuf limit and could be encoded with a larger budget.
138    ///
139    /// `len` is the exact encoded size (in bytes); `max_bytes` is the budget
140    /// that was exceeded.
141    #[error("message encoded size {len} exceeds the caller budget of {max_bytes} bytes")]
142    ExceedsBudget {
143        /// The exact encoded size of the message in bytes.
144        len: u32,
145        /// The caller-supplied budget that was exceeded.
146        max_bytes: u32,
147    },
148}