Skip to main content

moqtap_codec/
error.rs

1/// Maximum control message payload length: 2^16 - 1 bytes.
2pub const MAX_MESSAGE_LENGTH: usize = 65535;
3/// Maximum reason phrase length: 1024 bytes.
4pub const MAX_REASON_PHRASE_LENGTH: usize = 1024;
5/// Maximum GOAWAY new session URI length: 8192 bytes.
6pub const MAX_GOAWAY_URI_LENGTH: usize = 8192;
7/// Maximum full track name length: 4096 bytes.
8pub const MAX_FULL_TRACK_NAME_LENGTH: usize = 4096;
9/// Maximum track namespace tuple size: 32 elements.
10pub const MAX_NAMESPACE_TUPLE_SIZE: usize = 32;
11
12/// Errors produced during MoQT message encoding and decoding.
13///
14/// # Adding a variant
15///
16/// This enum is deliberately **not** `#[non_exhaustive]`, so that a session-close
17/// table matching it exhaustively fails to compile until a new variant has been
18/// placed on each of the drafts — either among the rules that draft
19/// answers with a close or among the ones it names and does not. A wildcard arm
20/// would make each draft's decision silently, all in the direction of "no
21/// rule", and a missing arm and a deliberate exclusion look identical from
22/// inside such a table.
23#[derive(Debug, thiserror::Error, PartialEq, Eq, Clone)]
24pub enum CodecError {
25    /// Unknown or unsupported message type identifier.
26    #[error("unknown message type: 0x{0:x}")]
27    UnknownMessageType(u64),
28    /// Not enough bytes in the buffer to complete decoding.
29    #[error("insufficient bytes")]
30    UnexpectedEnd,
31    /// Control message payload exceeds [`MAX_MESSAGE_LENGTH`].
32    #[error("message too long: {0} bytes (max {MAX_MESSAGE_LENGTH})")]
33    MessageTooLong(usize),
34    /// Variable-length integer encoding/decoding error.
35    #[error("varint error: {0}")]
36    VarInt(#[from] crate::varint::VarIntError),
37    /// Key-value pair encoding/decoding error.
38    #[error("kvp error: {0}")]
39    Kvp(#[from] crate::kvp::KvpError),
40    /// A decoded field value is not valid for its type.
41    #[error("invalid field value")]
42    InvalidField,
43    /// Namespace tuple element count is outside the range the caller allows.
44    ///
45    /// The upper bound is [`MAX_NAMESPACE_TUPLE_SIZE`] everywhere. The lower
46    /// bound is per-draft, and three wordings carry two rules. Drafts 07
47    /// through 14 define a Track Namespace as "an ordered N-tuple of bytes
48    /// where N can be between 1 and 32"; drafts 15 and 16 rename the elements
49    /// to Track Namespace Fields and keep the 1; drafts 17 and later lower it
50    /// to 0. So an empty tuple is refused only through draft-16.
51    #[error("namespace tuple size {0} is not allowed here (max {MAX_NAMESPACE_TUPLE_SIZE})")]
52    InvalidNamespaceTupleSize(usize),
53    /// A Track Namespace Field was declared with a length of zero.
54    ///
55    /// Drafts 16 through 19 all carry the same sentence in Section 2.4.1: "Each
56    /// Track Namespace Field Value MUST contain at least one byte. If an
57    /// endpoint receives a Track Namespace Field with a Track Namespace Field
58    /// Length of 0, it MUST close the session with a PROTOCOL_VIOLATION."
59    #[error("track namespace field is empty; each field must contain at least one byte")]
60    EmptyNamespaceField,
61    /// Full track name exceeds [`MAX_FULL_TRACK_NAME_LENGTH`].
62    #[error("track namespace or full track name exceeds {MAX_FULL_TRACK_NAME_LENGTH} bytes")]
63    TrackNameTooLong,
64    /// A requested range ends before it starts.
65    ///
66    /// Every draft states it, in the wording its fields have at the time.
67    /// Draft-07 Section 6.4 and Section 6.7: "EndGroup and EndObject MUST
68    /// specify the same or a later object than StartGroup and StartObject".
69    /// Draft-08 Section 7.4 through draft-14 Section 9.7, for the AbsoluteRange
70    /// filter: "End Group MUST specify the same or a larger Group than
71    /// specified in Start". Draft-12 Section 8.16 onwards, for FETCH: "End
72    /// Location MUST specify the same or a larger Location than Start
73    /// Location", which drafts 14 and later qualify with "for Standalone and
74    /// Absolute Joining Fetches".
75    ///
76    /// The two ends are reported as they appear on the wire, before the
77    /// draft's plus-one adjustments are undone, so the numbers here are the
78    /// ones a peer would read out of the frame.
79    #[error("range from group {0} object {1} ends at group {2} object {3}, which is earlier")]
80    InvalidRange(u64, u64, u64, u64),
81    /// A parameter's value is not the shape the parameter's own type implies.
82    ///
83    /// Drafts 07 through 10 state it once each, in the section that gives the
84    /// Parameter format: "If a receiver understands a parameter type, and the
85    /// parameter length implied by that type does not match the Parameter Length
86    /// field, the receiver MUST terminate the session with error code 'Parameter
87    /// Length Mismatch'." Each of those drafts assigns that code its own number
88    /// in the session termination registry. Drafts 11 and later drop the
89    /// sentence along with the Parameter framing it describes.
90    ///
91    /// The parameter reported is the one whose value disagreed with its type.
92    /// Which namespace the type is read in matters: a setup 0x02 is a
93    /// MAX_SUBSCRIBE_ID integer and a version-specific 0x02 is an
94    /// AUTHORIZATION INFO string.
95    #[error("parameter type {0} carries a value of the wrong length for its type")]
96    ParameterLengthMismatch(u64),
97    /// A key-value pair's value is not the serialization its own Type defines.
98    ///
99    /// Drafts 11 through 19 state it once each, in the section that gives the
100    /// Key-Value-Pair format. Drafts 14 and 15 word it: "If a receiver
101    /// understands a Type, and the following Value or Length/Value does not
102    /// match the serialization defined by that Type, the receiver MUST
103    /// terminate the session with error code KEY_VALUE_FORMATTING_ERROR".
104    /// Drafts 16 through 19 say close where those two say terminate, and
105    /// drafts 11 through 13 spell the code 'Key-Value Formatting Error'. Every
106    /// one of the nine assigns it a number in the session termination
107    /// registry.
108    ///
109    /// This is the successor to [`CodecError::ParameterLengthMismatch`], which
110    /// drafts 07 through 10 state about the Parameter framing they had instead.
111    /// The two never overlap: no draft states both, and the earlier rule is
112    /// about a declared length disagreeing with a type while this one is about
113    /// the bytes themselves.
114    ///
115    /// The rule is conditional on understanding the Type, so it reaches only the
116    /// types a draft defines a serialization for. A parameter this codec cannot
117    /// name carries bytes no rule here describes, and refusing it would close
118    /// sessions over extensions the drafts leave room for.
119    ///
120    /// `key` is the parameter type as the frame spelled it, in the namespace it
121    /// was read in — AUTHORIZATION TOKEN is 0x01 on draft-11 and 0x03 on drafts
122    /// 12 through 19, and a setup 0x01 is a PATH on draft-11 rather than a token
123    /// at all. `detail` says which way the value failed to match, because the
124    /// serialization is a structure rather than a length and "malformed" alone
125    /// leaves the reader to re-derive it.
126    #[error(
127        "key-value pair of type {key} does not match the serialization that type defines: {detail}"
128    )]
129    KeyValueFormatting {
130        /// The parameter type whose value did not match, as the frame spelled
131        /// it.
132        key: u64,
133        /// How the value failed to match the serialization.
134        detail: &'static str,
135    },
136    /// A control message carried a Message Parameter whose type its draft does
137    /// not define.
138    ///
139    /// Drafts 16, 17, 18 and 19 state it in the paragraph that introduces
140    /// parameters: "All Message Parameters MUST be defined in the negotiated
141    /// version of MOQT or negotiated via Setup Options. An endpoint that
142    /// receives an unknown Message Parameter MUST close the session with
143    /// PROTOCOL_VIOLATION." Drafts 17 and later add the reasoning — "Because the
144    /// receiver has to understand every Message Parameter, there is no need for
145    /// a mechanism to skip unknown parameters" — and draft-19 draws the
146    /// consequence for the framing: "Because unknown parameters cannot be
147    /// skipped, the block is bounded by a parameter count rather than a length."
148    /// Drafts 07 through 15 are the other way round and this must not reach
149    /// them. They say "Receivers MUST allow duplicates of unknown parameters",
150    /// which presumes unknown parameters arrive and are carried; refusing one
151    /// there would close a session over an extension those drafts leave room
152    /// for. Draft-16 is where the sentence narrows to *unknown **Setup**
153    /// Parameters*, in the same paragraph that adds the close — one edit, both
154    /// halves.
155    ///
156    /// Setup Parameters keep the older behaviour on every draft, which is why
157    /// this is about one namespace and not both. Drafts 16 through 19 all say a
158    /// receiver ignores an unrecognised Setup Option or Setup Parameter, so a
159    /// type unknown in that namespace is carried and only a type unknown in the
160    /// message namespace ends the session.
161    #[error("message parameter type {0} is not one this draft defines")]
162    UnknownMessageParameter(u64),
163    /// A Message Parameter appeared in a message type its own definition does
164    /// not name.
165    ///
166    /// Drafts 17, 18 and 19 only, and the split is the whole reason this is a
167    /// variant rather than a shared rule. All the drafts state the first
168    /// half the same way and ten of them state the opposite consequence.
169    /// Draft-19 Section 10.2.1, draft-18 Section 10.2.1 and draft-17 Section
170    /// 9.3.1: "Each Message Parameter definition indicates the message types in
171    /// which it can appear. If it appears in some other type of message, the
172    /// receiving endpoint MUST close the connection with a PROTOCOL_VIOLATION."
173    /// Draft-16 Section 9.2.2 and, under the older name Version Specific
174    /// Parameters, drafts 07 through 15, end the same sentence "it MUST be
175    /// ignored". Raising this on any of those ten would close a session over
176    /// traffic they oblige an endpoint to tolerate, so the decoder never does.
177    ///
178    /// What each draft's own text settles, and what it leaves open:
179    ///
180    /// * A parameter's scope is the set of message types named as the
181    ///   destination of its "MAY appear in" sentence, with trailing and
182    ///   parenthesised qualifiers read as describing one of those destinations
183    ///   rather than adding another. Draft-17's LARGEST_OBJECT "MAY appear in
184    ///   SUBSCRIBE_OK, PUBLISH or in REQUEST_OK (in response to REQUEST_UPDATE
185    ///   or TRACK_STATUS)" scopes three message types, not five, which is how
186    ///   drafts 18 and 19 write the same rule once the responses have names of
187    ///   their own.
188    /// * Half the response names are one wire type. Draft-19 Section 10.5:
189    ///   "This document uses the shorthand PUBLISH_OK, REQUEST_UPDATE_OK,
190    ///   TRACK_STATUS_OK, SUBSCRIBE_NAMESPACE_OK, and PUBLISH_NAMESPACE_OK to
191    ///   refer to a REQUEST_OK sent in response to the corresponding request
192    ///   type." Which one a given REQUEST_OK is depends on the request its
193    ///   Request ID answers, which is session state and not in the frame, so
194    ///   every name that resolves to REQUEST_OK widens the same set and a
195    ///   REQUEST_OK is held only to their union.
196    ///
197    /// Both readings err toward carrying the parameter, which is the direction
198    /// a rule that ends sessions should be wrong in.
199    ///
200    /// `key` is the absolute parameter type after any delta encoding is
201    /// resolved, and `message_type` is the type id off the wire, so a log names
202    /// the pair the sender actually wrote.
203    #[error("message parameter type {key} may not appear in message type {message_type}")]
204    ParameterOutOfScope {
205        /// The parameter type that was out of scope, absolute.
206        key: u64,
207        /// The message type it arrived in, as its id on the wire.
208        message_type: u64,
209    },
210    /// A Message Parameter carried a value outside the range its type allows.
211    ///
212    /// Drafts 15 through 19 give several parameters a range and answer anything
213    /// outside it with a close. GROUP_ORDER: "The allowed values are Ascending
214    /// (0x1) or Descending (0x2). If an endpoint receives a value outside this
215    /// range, it MUST close the session with PROTOCOL_VIOLATION." FORWARD says
216    /// the same of 0 and 1. Drafts 15 and 16 add SUBSCRIBER_PRIORITY — "The
217    /// range is restricted to 0-255" — which drafts 17 and later do not need,
218    /// having made the parameter a uint8 so that nothing outside the range can
219    /// be spelled. Draft-15 alone carries DYNAMIC_GROUPS as a Message Parameter,
220    /// where "Values larger than 1 are a Protocol Violation"; draft-16 moved it
221    /// into the extension header namespace, which this codec carries as opaque
222    /// bytes.
223    ///
224    /// Not draft-15's PUBLISHER_PRIORITY. It says "Priorities above 255 are
225    /// invalid" and stops there, naming no consequence, where every parameter
226    /// above states one in the next clause. The contrast is within one section,
227    /// so the omission is the draft's and not an oversight to be read past.
228    ///
229    /// Nor the Group Order and Forward *fields* of drafts 07 through 14, which
230    /// are a different serialization and are answered separately — Forward by
231    /// [`CodecError::InvalidForward`], Group Order by nothing, for the reason
232    /// given there.
233    ///
234    /// `key` is the absolute parameter type, after any delta encoding is
235    /// resolved, so a log names the type the sender meant rather than the
236    /// increment it wrote.
237    #[error(
238        "message parameter type {key} carries value {value}, which is outside the range it allows"
239    )]
240    ParameterValueOutOfRange {
241        /// The parameter type whose value was out of range, absolute.
242        key: u64,
243        /// The value as it arrived.
244        value: u64,
245    },
246    /// A Track Extension or Track Property carried a value outside the range its
247    /// type allows.
248    ///
249    /// A separate namespace from [`CodecError::ParameterValueOutOfRange`], and
250    /// separate for a reason rather than for tidiness: the two registries assign
251    /// the same numbers to different things. Type 0x22 is the GROUP_ORDER
252    /// Message Parameter and it is also DEFAULT_PUBLISHER_GROUP_ORDER, which is
253    /// a property of the track rather than a preference expressed by one
254    /// subscriber. Type 0x30 is DYNAMIC_GROUPS in the second namespace and is
255    /// unassigned in the first from draft-16 on. A single variant covering both
256    /// would name a type without saying which table to read it in.
257    ///
258    /// Draft-16 states the rules of the extension header namespace and drafts
259    /// 17, 18 and 19 restate them of the Track Property namespace that replaced
260    /// it. Two types restrict their range and answer anything outside it with a
261    /// close. DEFAULT_PUBLISHER_GROUP_ORDER: "The allowed values are Ascending
262    /// (0x1) or Descending (0x2). If an endpoint receives a value outside this
263    /// range, it MUST close the session with PROTOCOL_VIOLATION." DYNAMIC_GROUPS:
264    /// "The allowed values are 0 or 1... If an endpoint receives a value larger
265    /// than 1, it MUST close the session with PROTOCOL_VIOLATION."
266    ///
267    /// Draft-16 adds a third, and only draft-16: "DELIVERY_TIMEOUT, if present,
268    /// MUST contain a value greater than 0. If an endpoint receives a
269    /// DELIVERY_TIMEOUT equal to 0 it MUST close the session with
270    /// PROTOCOL_VIOLATION." Draft-17 renamed the type to
271    /// OBJECT_DELIVERY_TIMEOUT and states no range for it, so the rule ends
272    /// where the name does.
273    ///
274    /// Not DEFAULT_PUBLISHER_PRIORITY, on any of the four. "Priorities above 255
275    /// are invalid" names no consequence, in a section where its neighbours
276    /// name one in the next clause. The same contrast excludes draft-15's
277    /// PUBLISHER_PRIORITY from [`CodecError::ParameterValueOutOfRange`], and it
278    /// is the draft's distinction both times.
279    ///
280    /// `key` is the absolute type, after any delta encoding is resolved.
281    #[error(
282        "track property type {key} carries value {value}, which is outside the range it allows"
283    )]
284    TrackPropertyValueOutOfRange {
285        /// The extension or property type whose value was out of range,
286        /// absolute.
287        key: u64,
288        /// The value as it arrived.
289        value: u64,
290    },
291    /// A Forward field carried a value other than zero or one.
292    ///
293    /// Drafts 11 through 14 carry the field, and state the rule in two wordings.
294    /// SUBSCRIBE and SUBSCRIBE_UPDATE, on all four: "Forward: If 1, Objects
295    /// matching the subscription are forwarded to the subscriber. If 0, Objects
296    /// are not forwarded to the subscriber. Any other value is a protocol error
297    /// and MUST terminate the session with a Protocol Violation". PUBLISH, added
298    /// in draft-12: "Any value other than 0 or 1 is a Protocol Violation."
299    /// Draft-14 spells both codes PROTOCOL_VIOLATION and is otherwise unchanged.
300    ///
301    /// PUBLISH_OK, also from draft-12, is the one site that names no
302    /// consequence: "Forward: The Forward State for this subscription, either 0
303    /// (don't forward) or 1 (forward)." It is reported here all the same. The
304    /// field carries the same two values in every message that has one, three of
305    /// the four sites state the close outright, and the sentence enumerates 0
306    /// and 1 without giving a third value any meaning — so this is the same rule
307    /// stated shorter, not a permission. Reading an omission the other way is
308    /// how a wrong claim gets in: on Group Order, drafts 12 through 14 do state
309    /// the 0x0 rule for SUBSCRIBE_OK, PUBLISH and FETCH_OK, so a reading that has
310    /// them silent about it is wrong about all three.
311    ///
312    /// Drafts 07 through 10 have no such field. Drafts 15 and later carry
313    /// forwarding as the FORWARD parameter instead, under the same rule but a
314    /// different serialization; that form is
315    /// [`CodecError::ParameterValueOutOfRange`].
316    #[error("forward field carries {0}, which is neither zero nor one")]
317    InvalidForward(u8),
318    /// A subscription filter names a Filter Type no draft in its range assigns.
319    ///
320    /// Every draft with a Filter Type states the rule, and they do not state
321    /// the same consequence. Drafts 20 and 21 have no Filter Type: their
322    /// filter's shape comes from its length. Drafts 07 through 13: "A filter
323    /// type other than the above MUST be treated as error", which names no code
324    /// and no close. Draft-14:
325    /// "An endpoint that receives a filter type other than the above MUST be
326    /// close the session with PROTOCOL_VIOLATION", the typo being the draft's.
327    /// Drafts 15 through 19 say the same without the typo, and draft-22, whose
328    /// `Location Filter Type` numbers its forms afresh, writes it as "Any other
329    /// Location Filter Type is a PROTOCOL_VIOLATION." So the same value in the
330    /// same place is a refused message on the first seven drafts and a session
331    /// close on the later ones, and only the per-draft session table can tell
332    /// them apart.
333    ///
334    /// The assigned set is not constant either. Drafts 07 and 08 assign 0x1 as
335    /// Latest Group, drafts 09 and 10 withdraw it and list three types, and
336    /// drafts 11 and later reinstate 0x1 as Next Group Start — a different
337    /// meaning at the same number. A decoder that accepts the union would read a
338    /// draft-09 SUBSCRIBE the draft requires it to reject.
339    ///
340    /// The serialization moves as well. Drafts 07 through 14 carry the Filter
341    /// Type as a field of SUBSCRIBE and its relatives; drafts 15 through 19
342    /// carry it as the first field inside the length-prefixed filter parameter,
343    /// which is a place a reader of the field has to know to look. Draft-22
344    /// carries it first in a LOCATION_FILTER parameter that has no length at
345    /// all, so there an unknown type leaves the reader unable to find the end
346    /// of the parameter, let alone the next one.
347    #[error("filter type {0} is not one this draft assigns")]
348    InvalidFilterType(u64),
349    /// A FETCH names a Fetch Type no draft in its range assigns.
350    ///
351    /// The sentence next to the Filter Type one, and it moves the same way.
352    /// Drafts 08 through 13: "A Fetch Type other than 0x1, 0x2 or 0x3 MUST be
353    /// treated as an error", naming no code and no close — 0x3 being absent from
354    /// the sentence on drafts 08, 09 and 10, which assign only two types.
355    /// Draft-14: "An endpoint that receives a Fetch Type other than 0x1, 0x2 or
356    /// 0x3 MUST be close the session with a PROTOCOL_VIOLATION", carrying the
357    /// same missing word as its Filter Type sentence. Drafts 15 through 19 say it
358    /// without the typo. Draft-07 has no FETCH at all.
359    ///
360    /// Like the Filter Type, the value decides which fields follow it: a
361    /// Standalone fetch carries a Track Namespace, a Track Name and a range, and
362    /// a joining fetch carries a Request ID and an offset. A reader that cannot
363    /// name the type cannot find the end of the message, which is why the later
364    /// drafts answer it with a close rather than by ignoring the field.
365    #[error("fetch type {0} is not one this draft assigns")]
366    InvalidFetchType(u64),
367    /// A subscription filter parameter's value is not a filter.
368    ///
369    /// Drafts 15 and 16 state it of this parameter directly: "If the length of
370    /// the Subscription Filter does not match the parameter length, the publisher
371    /// MUST close the session with PROTOCOL_VIOLATION." Drafts 17 through 19
372    /// drop that sentence and leave the general one, which every draft from 15
373    /// on also carries: "If a receiver understands a Type, and the following
374    /// Value or Length/Value does not match the serialization defined by that
375    /// Type, the receiver MUST close the session with error code
376    /// KEY_VALUE_FORMATTING_ERROR."
377    ///
378    /// Two sentences, two codes, one malformation — which is why this is a
379    /// variant of its own rather than reported as
380    /// [`CodecError::KeyValueFormatting`]. A filter three bytes long inside a
381    /// four-byte parameter ends a draft-16 session with PROTOCOL_VIOLATION and a
382    /// draft-17 session with KEY_VALUE_FORMATTING_ERROR, and the session tables
383    /// are where that difference belongs.
384    ///
385    /// A Filter Type outside the assigned set is not this: the filter's own
386    /// section names PROTOCOL_VIOLATION for that on all five drafts, and it is
387    /// [`CodecError::InvalidFilterType`].
388    ///
389    /// `detail` says which way the value failed, because "malformed" alone
390    /// leaves the reader to work out whether the filter ran short or the
391    /// parameter ran long.
392    #[error("subscription filter parameter is not a filter: {detail}")]
393    SubscriptionFilterMalformed {
394        /// How the value failed to be a filter.
395        detail: &'static str,
396    },
397    /// An AbsoluteRange filter's End Group Delta carries the range past the end
398    /// of the number space.
399    ///
400    /// Drafts 17 and later replaced the absolute End Group with a delta measured
401    /// from the Start Location's Group, which makes the last group in range a
402    /// sum rather than a field. Drafts 18 and 19 answer the sum leaving the
403    /// range: "Otherwise, the last Group ID to be delivered will be the Group ID
404    /// in Start Location plus the End Group Delta. If the resulting Group ID
405    /// would be greater than 2^64 - 1, the endpoint MUST close the session with
406    /// a PROTOCOL_VIOLATION."
407    ///
408    /// Draft-17 introduced the delta and states no such sentence, so it is
409    /// absent from that draft's session table. Drafts 15 and 16 write the End
410    /// Group out in full and can express nothing to overflow.
411    #[error(
412        "filter start group {start_group} plus end group delta {delta} leaves the 64-bit range"
413    )]
414    FilterEndGroupOverflow {
415        /// The Group ID of the filter's Start Location.
416        start_group: u64,
417        /// The End Group Delta as the filter carried it.
418        delta: u64,
419    },
420    /// An end-of-track object states an Object ID other than zero.
421    ///
422    /// Drafts 08, 09 and 10 describe Object Status 0x5 as "end of Track. GroupID
423    /// is one greater than the largest group produced in this track and the
424    /// ObjectId is zero", and continue: "An object with this status that has a
425    /// Group ID less than or equal to any other Group ID, or an Object ID other
426    /// than zero, is a protocol error, and the receiver MUST terminate the
427    /// session." The Group ID half needs the largest group seen on the track and
428    /// is not settleable from one header; the Object ID half is, and is what this
429    /// reports. Draft-07 assigns no 0x5 and drafts 11 and later drop the
430    /// sentence.
431    #[error("end-of-track object states object id {0}; an end of track ends at object zero")]
432    EndOfTrackObjectId(u64),
433    /// A delta-encoded key would exceed 2^64 - 1 once the delta is added to the
434    /// previous key.
435    ///
436    /// Drafts 16, 17, 18 and 19 all say, in Section 1.4.3: "The previous Type
437    /// value plus the Delta Type MUST NOT be greater than 2^64 - 1. If a Delta
438    /// Type is received that would be too large, the Session MUST be closed
439    /// with a PROTOCOL_VIOLATION." Delta encoding arrives with draft-16;
440    /// drafts 15 and earlier write absolute types and cannot reach this.
441    #[error("delta-encoded key {0} + {1} exceeds 2^64 - 1")]
442    KeyDeltaOverflow(u64, u64),
443    /// A caller asked to encode a parameter list that is not in ascending order
444    /// by type.
445    ///
446    /// Drafts 17, 18 and 19 require it in as many words: "Parameters MUST be
447    /// serialized in ascending order by Type." Draft-16 delta-encodes types
448    /// without stating that sentence, but the constraint is the same there and
449    /// is structural rather than stated: the delta is an unsigned difference
450    /// from the previous type, so a descending pair has no representation at
451    /// all. Encoding one anyway wraps the subtraction and emits a nine-byte
452    /// delta the peer resolves to an unrelated key, which is why draft-16
453    /// reports this too.
454    #[error("parameter type {1} follows {0}; parameters must be in ascending order by type")]
455    ParametersOutOfOrder(u64, u64),
456    /// The same parameter type appears twice in one message, and its definition
457    /// does not allow that.
458    ///
459    /// Every draft from 07 to 20 states the sender's half: "Senders MUST NOT
460    /// repeat the same Parameter Type in a message" — drafts 11 and later
461    /// adding "unless the parameter definition explicitly allows multiple
462    /// instances of that type to be sent in a single message." The receiver's
463    /// half is a SHOULD, and from draft-11 it carries a limit that makes the
464    /// rule asymmetric: "Receivers MUST allow duplicates of unknown
465    /// parameters." A receiver may therefore refuse a repeat only of a type its
466    /// own draft names, while a sender may repeat nothing it is not granted.
467    ///
468    /// One type is granted repeats, from draft-11 onward: AUTHORIZATION TOKEN,
469    /// numbered 0x01 on draft-11 and 0x03 on drafts 12 through 19. It is not
470    /// reported here. Drafts 07 through 10 state neither the exemption clause
471    /// nor the unknown-duplicates sentence, so on those four the rule is
472    /// symmetric and every repeat is refused in both directions.
473    ///
474    /// Setup Parameters and Version Specific Parameters are separate
475    /// namespaces that assign different meanings to the same number, so the
476    /// exemption is per namespace: on draft-11, 0x01 is the repeatable
477    /// AUTHORIZATION TOKEN in a SUBSCRIBE and the non-repeatable PATH in a
478    /// CLIENT_SETUP.
479    #[error("parameter type {0} appears more than once")]
480    DuplicateParameter(u64),
481    /// A delta-encoded Object ID would exceed 2^64 - 1 once the delta is added
482    /// to the previous Object ID on the same stream.
483    ///
484    /// Drafts 18 through 20 Section 11.4.2, and drafts 21 through 23 Section 11.3.1: "The
485    /// Object ID Delta + 1 is added to the previous Object ID in the Subgroup
486    /// stream if there was one... If the resulting Object ID would be greater
487    /// than 2^64 - 1, the endpoint MUST close the session with a
488    /// PROTOCOL_VIOLATION."
489    ///
490    /// Drafts 14 through 17 Section 10.4.2 describe the same arithmetic and
491    /// state no consequence, so on those four this is a decode failure and
492    /// nothing more. The delta encoding does not exist before draft-14, which
493    /// is why the range starts there rather than at the first draft with a
494    /// subgroup stream.
495    ///
496    /// Distinct from [`CodecError::InvalidField`], which is too coarse for this
497    /// rule: a caller could not tell the wrap from a dozen unrelated
498    /// malformations, and so could not act on the rule.
499    #[error("object id {0} + {1} + 1 exceeds 2^64 - 1")]
500    ObjectIdOverflow(u64, u64),
501    /// An Object with Object Status 'Object Does Not Exist' carries extension
502    /// headers.
503    ///
504    /// Drafts 11 through 14 state it once each — draft-11 Section 9.1.1.2,
505    /// drafts 12 and 13 Section 9.2.1.2, draft-14 Section 10.2.1.2 — and the
506    /// first three word it: "Any Object may have extension headers except those
507    /// with Object Status 'Object Does Not Exist'. If an endpoint receives a
508    /// non-existent Object containing extension headers it MUST close the
509    /// session with a Protocol Violation." Draft-14 states the same sentence
510    /// with the code spelled PROTOCOL_VIOLATION.
511    ///
512    /// The rule names one status and no others, so extensions beside End of
513    /// Group or End of Track are legal on those four drafts and are not
514    /// reported here. Drafts 15 and later replaced this narrow form with the
515    /// general one — extensions, later properties, are permitted only beside
516    /// Normal — which is a different rule with a different subject and is
517    /// reported by the carriers' own `extensions_permitted` predicates.
518    ///
519    /// Drafts 07 through 10 state neither form.
520    ///
521    /// All three carriers that announce a status reach this, in both
522    /// directions: an object on a subgroup stream, an object on a fetch stream,
523    /// and a status datagram. A plain datagram has no status field and is the
524    /// one carrier that cannot break the rule.
525    ///
526    /// Distinct from [`CodecError::InvalidField`], which is too coarse for this
527    /// rule: a caller could not tell it from a dozen unrelated malformations, so
528    /// a session could not be closed over it without closing sessions the drafts
529    /// do not ask to be closed.
530    #[error("object with status 'object does not exist' carries {0} bytes of extension headers")]
531    ExtensionsOnNonExistentObject(usize),
532    /// An object's property block (Extension Headers before draft-17) cannot be
533    /// read as Key-Value-Pairs: a property runs past the end of the block, or
534    /// Immutable Properties hold another Immutable Properties.
535    ///
536    /// Either one makes the Track malformed: draft-14 and draft-16 Section
537    /// 11.2, draft-15 Section 11.1, draft-17 Section 11.6, drafts 18-20 Section
538    /// 12.7, drafts 21-23 Section 10.7. No draft closes the session over it.
539    ///
540    /// Raised by the readers that hand back a whole object. The framing readers
541    /// a relay uses delimit the block by its length and never read inside it.
542    #[error("malformed property block at byte {offset}: {detail}")]
543    MalformedObjectProperties {
544        /// Where in the block the property that cannot be read begins.
545        offset: usize,
546        /// What is wrong with it.
547        detail: String,
548    },
549    /// An object arrived carrying a payload the draft gives it no room for.
550    ///
551    /// All the drafts state the rule, in two phrasings. Drafts 07 through
552    /// 18 say it of the status code — draft-07 Section 7.1.1.1, drafts 08 and
553    /// 09 Section 8.1.1.1, drafts 10 and 11 Section 9.1.1.1, drafts 12 and 13
554    /// Section 9.2.1.1, drafts 14 through 17 Section 10.2.1.1, draft-18 Section
555    /// 11.2.1.1: "Any object with a status code other than zero MUST have an
556    /// empty payload." Drafts 19 and 20 state it of a registry instead, both in
557    /// their Section 11.2.1.1: "An Object MUST have an empty payload unless its
558    /// Object Status value is registered as permitting a payload in the Object
559    /// Status registry (Section 15.9). Of the values defined in this document,
560    /// only Normal (0x0) permits a payload." The two agree on every status those
561    /// documents define and differ in what a later one may add.
562    ///
563    /// `detail` separates the two ways an object can break it, because they are
564    /// different mistakes and the second is the one a decoder can be fooled by:
565    ///
566    /// * The framing already said there would be no payload. A datagram whose
567    ///   Type sets the STATUS bit carries a status in the payload's place, so
568    ///   bytes after it are not a short payload or an odd one — they are bytes
569    ///   the frame does not define. This bites hardest at status Normal, whose
570    ///   status alone would report a payload as permitted, and a caller that
571    ///   treats what is left as the payload hands the application content the
572    ///   publisher never framed as content.
573    /// * The status forbids one. The registry rule above, reached where a
574    ///   caller holds a status and a payload together and the framing has not
575    ///   already ruled one of them out.
576    ///
577    /// **No draft turns this into a close.** The sentence is a MUST on the
578    /// sender with no receiver action named, and the "SHOULD be treated as a
579    /// protocol error" beside it belongs to the neighbouring rule about
580    /// unassigned status values. So every draft's session-close table places it
581    /// among the rules they state and do not end a session over — which is a
582    /// decision this variant makes visible, and one
583    /// [`CodecError::InvalidField`] was making by accident.
584    ///
585    /// Distinct from that variant for the reason
586    /// [`CodecError::ExtensionsOnNonExistentObject`] is: an error a caller
587    /// cannot name is one no test can assert and no log can explain.
588    #[error("object with status {status} carries {len} bytes of payload; {detail}")]
589    PayloadNotPermitted {
590        /// The object's status as it arrived on the wire.
591        status: u64,
592        /// How many bytes followed it.
593        len: usize,
594        /// Which of the two rules the bytes broke.
595        detail: &'static str,
596    },
597    /// A request message's Required Request ID Delta names a dependency below
598    /// zero.
599    ///
600    /// Draft-17 Section 9.2: "An endpoint MUST close the session with
601    /// INVALID_REQUIRED_REQUEST_ID if it receives a delta where 2 × Required
602    /// Request ID Delta exceeds the Request ID." Draft-18 removed the field.
603    #[error("required request id delta {1} is too large for request id {0}")]
604    InvalidRequiredRequestIdDelta(u64, u64),
605    /// A unidirectional stream announced a type its draft's stream table does
606    /// not assign.
607    ///
608    /// Every draft from 07 to 20 requires the session to end for this, in one
609    /// of two phrasings. Draft-07 and drafts 17 through 19 say "An endpoint
610    /// that receives an unknown stream type MUST close the session"; drafts 08
611    /// through 16 fold the streams and the datagrams into one sentence, "an
612    /// unknown stream or datagram type", whose second half is
613    /// [`CodecError::UnknownDatagramType`]. No draft in the range is silent,
614    /// and neither phrasing is a hint that the other draft's rule is weaker.
615    ///
616    /// What the tables assign moves across the range, so the set this reports
617    /// on is per-draft rather than shared. Draft-07 has a single table covering
618    /// streams and datagrams together, which is why an OBJECT_DATAGRAM type at
619    /// the head of a draft-07 stream is *not* unknown; drafts 08 onward split
620    /// them into two tables with independent numbering; drafts 17 through 19
621    /// add SETUP, and drafts 18 and 19 add PADDING, both of which are assigned
622    /// stream types that a subgroup reader must refuse without reporting this.
623    ///
624    /// A stream announcing an assigned type this reader cannot read is not this
625    /// error: the value is one the draft defines, and the disagreement is with
626    /// the caller rather than with the draft. Those stay
627    /// [`CodecError::InvalidField`]. The distinction is the whole point of the
628    /// variant — reporting an assigned type as unknown closes sessions over
629    /// streams the draft permits, which is the more costly way to be wrong.
630    #[error("stream type {0} is not one this draft assigns")]
631    UnknownStreamType(u64),
632    /// A datagram announced a type its draft's datagram table does not assign.
633    ///
634    /// The datagram half of the rule above, and stated by all the drafts
635    /// for the same reason: drafts 08 through 16 name streams and datagrams in
636    /// one sentence, and drafts 17, 18 and 19 give the datagrams their own —
637    /// "An endpoint that receives an unknown datagram type MUST close the
638    /// session." Draft-07 alone numbers its datagrams in the stream table, so
639    /// its datagram types are reported by [`CodecError::UnknownStreamType`] and
640    /// this variant is never produced there.
641    ///
642    /// Separate from the stream variant because the two number spaces are
643    /// separate from draft-08 on: 0x05 is FETCH_HEADER on a stream and an
644    /// assigned OBJECT_DATAGRAM form in several drafts' datagram tables, so a
645    /// single variant could not say which table had been consulted.
646    #[error("datagram type {0} is not one this draft assigns")]
647    UnknownDatagramType(u64),
648    /// A subgroup stream header's Type was inside the form its draft defines,
649    /// but held a combination the draft separately names as invalid.
650    ///
651    /// Distinct from [`CodecError::UnknownStreamType`], which reports a value
652    /// no table assigns. Drafts 16 through 23 describe the subgroup Type as a
653    /// bit field rather than as a list of code points, and then rule
654    /// combinations out *within* the form: on each of them a SUBGROUP_ID_MODE of
655    /// 0b11, and from draft-20 also a Type that leaves the subgroup form's own
656    /// bit clear or that runs past the one-byte flags space. The enclosing
657    /// form is assigned, so calling these unknown would misname them; the
658    /// drafts call them invalid and require a close, with PROTOCOL_VIOLATION
659    /// through draft-22 and INVALID_STREAM_HEADER in draft-23.
660    ///
661    /// Separate from [`CodecError::InvalidDatagramTypeValue`] because the
662    /// drafts state the two as separate sentences in separate sections — "If
663    /// an endpoint receives a stream header with any of these" against "If an
664    /// endpoint receives a datagram with any of these". A single variant
665    /// spanning both could not say which of the two sentences a frame broke,
666    /// and `raw` cannot be made to say it either: the two Type spaces overlap,
667    /// so deriving the namespace from the number would be this crate guessing
668    /// which table had been consulted. A consumer that publishes the rule
669    /// beside the refusal would then be right on half the frames and wrong on
670    /// the other half, with nothing in the row to say which.
671    ///
672    /// `detail` names which combination was seen, because the rule is a list
673    /// rather than a single condition and a log that says only "invalid" leaves
674    /// the reader to re-derive the bits.
675    #[error("stream header type {raw:#x} is one this draft names as invalid: {detail}")]
676    InvalidStreamTypeValue {
677        /// The Type value as it arrived, before any narrowing to a byte.
678        raw: u64,
679        /// Which of the draft's lists it fell into.
680        detail: &'static str,
681    },
682    /// A datagram's Type was inside the form its draft defines, but held a
683    /// combination the draft separately names as invalid.
684    ///
685    /// The datagram half of [`CodecError::InvalidStreamTypeValue`], which
686    /// carries the reason the two are separate variants rather than one.
687    /// Drafts 16 through 23 rule out a Type asking to be both an object status
688    /// and an end-of-group marker; drafts 20 through 23 add the bit reserved for a
689    /// datagram, and any other bit their form leaves unspecified.
690    ///
691    /// `detail` names which combination was seen, for the reason the stream
692    /// variant gives.
693    #[error("datagram type {raw:#x} is one this draft names as invalid: {detail}")]
694    InvalidDatagramTypeValue {
695        /// The Type value as it arrived, before any narrowing to a byte.
696        raw: u64,
697        /// Which of the draft's lists it fell into.
698        detail: &'static str,
699    },
700    /// A ContentExists field carried a value other than zero or one.
701    ///
702    /// Drafts 07 through 13 all state it in the same words: "Content Exists: 1
703    /// if an object has been published on this track, 0 if not. If 0, then the
704    /// Largest Group ID and Largest Object ID fields will not be present. Any
705    /// other value is a protocol error and MUST terminate the session with a
706    /// Protocol Violation". Draft-14 states the same sentence with the code
707    /// spelled PROTOCOL_VIOLATION. Draft-07 states it for SUBSCRIBE_OK
708    /// in Section 6.15 and SUBSCRIBE_DONE in Section 6.19; drafts 08 through 11
709    /// keep the SUBSCRIBE_OK site alone; drafts 12, 13 and 14 add PUBLISH.
710    /// Draft-15 removed the field, replacing it with the presence or absence of
711    /// a LARGEST_OBJECT parameter, so no draft from 15 on has one.
712    ///
713    /// The field is a single byte and it decides whether two more follow, so a
714    /// value that is neither leaves a reader with no way to know where the
715    /// message ends.
716    #[error("content exists field carries {0}, which is neither zero nor one")]
717    InvalidContentExists(u8),
718    /// A control message's declared Length disagrees with the fields it
719    /// carries.
720    ///
721    /// All the drafts state it in the same paragraph that gives the
722    /// message type registry, and only the code changes: drafts 07 through 10
723    /// say "If the length does not match the length of the message content, the
724    /// receiver MUST close the session", naming no code; drafts 11 through 18
725    /// name the Message Payload and answer with PROTOCOL_VIOLATION; draft-19
726    /// renames the field to Message Body and keeps the code.
727    ///
728    /// Both directions are the same rule and both are reported here. Fields that
729    /// stop short leave bytes unread — a trailing field the sender wrote and
730    /// this reader does not know about, or one it read at the wrong width.
731    /// Fields that run past the end wanted more bytes than the Length allowed,
732    /// which is the same disagreement seen from the other side.
733    /// The second case is why this cannot be left as
734    /// [`CodecError::UnexpectedEnd`]. That variant means *the message is still
735    /// arriving* everywhere else, and a reader loops on it rather than closing;
736    /// inside a buffer already bounded by the declared Length there is nothing
737    /// left to arrive, so running out there means something else entirely.
738    ///
739    /// Distinct from [`CodecError::InvalidField`], which is too coarse for the
740    /// leftover-bytes case: a caller could not tell it from a dozen unrelated
741    /// malformations, so a session could not be closed over it.
742    #[error("control message declares {declared} bytes of payload; {detail}")]
743    ControlMessageLengthMismatch {
744        /// The Length field the sender wrote.
745        declared: usize,
746        /// Which way the two disagreed, in words, because the useful number is
747        /// different in each direction and neither is knowable in the other.
748        detail: &'static str,
749    },
750    /// A control message's Length is larger than the receiver's
751    /// MAX_CONTROL_MESSAGE_SIZE, or one about to be sent is larger than the
752    /// peer's.
753    ///
754    /// Draft-23 Section 9: "If an endpoint receives a control message with a
755    /// length larger than its MAX_CONTROL_MESSAGE_SIZE, it MUST close the
756    /// session with FIELD_LENGTH_EXCEEDED." Drafts 11 through 22 cap the
757    /// Length at 2^16-1 by its width and report an oversized body on encode as
758    /// [`CodecError::MessageTooLong`].
759    #[error("control message body of {length} bytes exceeds the limit of {limit}")]
760    ControlMessageExceedsLimit {
761        /// The body length, as declared or as about to be written.
762        length: u64,
763        /// The MAX_CONTROL_MESSAGE_SIZE in force.
764        limit: u64,
765    },
766    /// A REQUEST_ERROR whose Error Code requires an Error Detail carries none.
767    ///
768    /// Draft-23 Section 9.4.2.1: "An endpoint that receives a REQUEST_ERROR
769    /// with Error Code REDIRECT and no REDIRECT Error Detail MUST close the
770    /// session with MALFORMED_MESSAGE."
771    #[error("REQUEST_ERROR code {error_code:#x} carries no Error Detail of type {detail_type:#x}")]
772    MissingErrorDetail {
773        /// The Error Code that requires the detail.
774        error_code: u64,
775        /// The Error Detail type it requires.
776        detail_type: u64,
777    },
778    /// A known Error Detail whose value is not the structure its Type defines.
779    ///
780    /// Draft-23 Section 9.4.2.1 gives the REDIRECT Error Detail a structure,
781    /// and draft-23 Section 8.3: "If a receiver understands a Type, and the
782    /// following Value or Length/Value does not match the serialization defined
783    /// by that Type, the receiver MUST close the session with
784    /// MALFORMED_KEY_VALUE."
785    #[error(
786        "error detail of type {detail_type:#x} is not the structure that type defines: {detail}"
787    )]
788    MalformedErrorDetail {
789        /// The Error Detail type.
790        detail_type: u64,
791        /// How the value failed to match.
792        detail: &'static str,
793    },
794    /// A SETUP whose AUTHORIZATION TOKEN option names an Alias with DELETE or
795    /// USE_ALIAS.
796    ///
797    /// SETUP is the first message on the control stream, so no Alias is
798    /// registered when it arrives. Draft-23 Section 9.1.4: "If a server
799    /// receives Alias Type DELETE (0x0) or USE_ALIAS (0x2) in a SETUP message,
800    /// it MUST close the session with ROLE_VIOLATION." At a client, Section
801    /// 8.9: "The receiver of a message referencing an Alias that is not
802    /// currently registered MUST reject the message with
803    /// UNKNOWN_AUTH_TOKEN_ALIAS." Which applies is the receiver's role.
804    #[error("SETUP carries an authorization token with Alias Type {alias_type:#x}")]
805    TokenAliasInSetup {
806        /// The Alias Type, DELETE (0x0) or USE_ALIAS (0x2).
807        alias_type: u64,
808    },
809    /// A Track Name with a length of zero.
810    ///
811    /// Draft-23 Section 2.4.1: "If an endpoint receives a Track Name with a
812    /// length of 0, it MUST close the session with a PROTOCOL_VIOLATION."
813    /// Drafts 07 through 22 allow an empty Track Name.
814    #[error("track name is empty; a track name must contain at least one byte")]
815    EmptyTrackName,
816    /// An AUTHORIZATION TOKEN whose Token structure cannot be decoded.
817    ///
818    /// Draft-23 Section 8.9: "If the Token structure cannot be decoded,
819    /// including an unknown Alias Type, the receiver MUST close the Session
820    /// with MALFORMED_AUTH_TOKEN." Drafts 11 through 22 report the same
821    /// failure as [`CodecError::KeyValueFormatting`].
822    #[error("authorization token in parameter type {key} cannot be decoded: {detail}")]
823    MalformedAuthToken {
824        /// The parameter or Setup Option type that carried the token.
825        key: u64,
826        /// How the token failed to decode.
827        detail: &'static str,
828    },
829    /// Track Properties in a REQUEST_OK that answers a request whose OK must
830    /// carry none.
831    ///
832    /// Draft-23 Section 9.3: Track Properties "are empty in PUBLISH_OK,
833    /// REQUEST_UPDATE_OK, SUBSCRIBE_NAMESPACE_OK and PUBLISH_NAMESPACE_OK. If
834    /// an endpoint receives Track Properties in one of these messages it MUST
835    /// close the session with INVALID_FIELD."
836    #[error("REQUEST_OK carries Track Properties where its request permits none")]
837    TrackPropertiesNotPermitted,
838    /// A Group ID or Object ID decoded from a delta on a fetch stream is
839    /// below 0 or above 2^64-1.
840    ///
841    /// Draft-23 Section 12.2: "DELTA_ENCODING_OVERFLOW (0x400): A value
842    /// decoded from a delta encoding is less than 0 or greater than 2^64 - 1."
843    #[error("fetch stream {detail} is outside 0 to 2^64 - 1")]
844    DeltaDecodingOverflow {
845        /// Which value overflowed.
846        detail: &'static str,
847    },
848    /// An Object on a fetch stream whose serialization cannot be decoded.
849    ///
850    /// Draft-23 Section 12.2: "MALFORMED_OBJECT (0x201): The serialization of
851    /// an Object on a data stream or in a datagram cannot be decoded, for
852    /// example a flag references a prior Object that does not exist."
853    #[error("fetch object cannot be decoded: {detail}")]
854    MalformedObject {
855        /// What could not be decoded.
856        detail: &'static str,
857    },
858    /// An Object whose Prior Group ID Gap or Prior Object ID Gap makes its
859    /// Track malformed.
860    ///
861    /// Draft-23 Section 10.8: "A Track is considered malformed (see Section
862    /// 12.1) if any of the following conditions are detected", and Section
863    /// 10.9 the same for Prior Object ID Gap. Only the conditions one Object,
864    /// or one subgroup stream, shows are detected here.
865    ///
866    /// Drafts 14-22 state the same conditions, in draft-14 Section 11.1,
867    /// draft-14 Section 11.3, draft-15 Section 11.1, draft-15 Section 11.2,
868    /// draft-16 Section 11.3, draft-16 Section 11.4, draft-17 Section 11.7,
869    /// draft-17 Section 11.8, draft-18 Section 12.8, draft-18 Section 12.9,
870    /// draft-19 Section 12.8, draft-19 Section 12.9, draft-20 Section 12.8,
871    /// draft-20 Section 12.9, draft-21 Section 10.8, draft-21 Section 10.9,
872    /// draft-22 Section 10.8 and draft-22 Section 10.9. Drafts 11-13 state
873    /// only the Prior Group ID Gap ones: draft-11 Section 10.1,
874    /// draft-12 Section 10.1 and draft-13 Section 10.1.
875    #[error("malformed track: {detail}")]
876    MalformedTrack {
877        /// Which condition was detected.
878        detail: String,
879    },
880    /// An Object Status the draft does not assign, on a subgroup stream or in
881    /// a datagram.
882    ///
883    /// Draft-23 Section 11.1.1: "If an endpoint receives any other value, it
884    /// SHOULD close the session with INVALID_OBJECT_STATUS (Section 12.2)."
885    #[error("Object Status {0:#x} is not an assigned status")]
886    UnknownObjectStatus(u64),
887    /// Reason phrase exceeds [`MAX_REASON_PHRASE_LENGTH`].
888    #[error("reason phrase exceeds {MAX_REASON_PHRASE_LENGTH} bytes")]
889    ReasonPhraseTooLong,
890    /// GOAWAY URI exceeds [`MAX_GOAWAY_URI_LENGTH`].
891    #[error("GOAWAY URI exceeds {MAX_GOAWAY_URI_LENGTH} bytes")]
892    GoAwayUriTooLong,
893    /// Draft not implemented or not enabled via feature flag.
894    #[error("unsupported draft: {0}")]
895    UnsupportedDraft(String),
896}
897
898impl CodecError {
899    /// Whether more bytes might complete this decode.
900    ///
901    /// A reader that owns a growing buffer asks this to tell *the input has
902    /// not all arrived* from *the input is wrong*: `true` means fill the
903    /// buffer and decode again, `false` means the bytes are what they are and
904    /// no amount of waiting improves them.
905    ///
906    /// # Why this is a predicate and not a variant test
907    ///
908    /// Running out of bytes has four spellings here, because a decode can run
909    /// out inside a nested decoder that reports in its own error type and each
910    /// one names the condition after itself:
911    ///
912    /// * [`CodecError::UnexpectedEnd`], from a field this module read;
913    /// * [`CodecError::VarInt`] carrying [`VarIntError::UnexpectedEnd`], from a
914    ///   varint whose length prefix promised bytes the buffer did not hold;
915    /// * [`CodecError::Kvp`] carrying [`KvpError::UnexpectedEnd`], and
916    /// * the same wrapped one level deeper as
917    ///   [`KvpError::VarInt`]`(`[`VarIntError::UnexpectedEnd`]`)`, from a
918    ///   key-value pair that ran out in its length or in its value.
919    ///
920    /// All four mean the same thing to a caller and only the first announces
921    /// it in the variant name. That is not a hypothetical: a reader matching
922    /// the first alone treated a subgroup object whose leading varint had not
923    /// arrived yet as a malformed stream, and reported `insufficient bytes for
924    /// varint decoding` for an object that was merely still in flight. The
925    /// condition is one fact about a buffer, so it is answered in one place
926    /// rather than re-derived by every reader that has to know it.
927    ///
928    /// # What is deliberately not here
929    ///
930    /// [`CodecError::ControlMessageLengthMismatch`] is the case that looks
931    /// like this one and is its opposite, and its own documentation says why:
932    /// inside a buffer already bounded by a declared Length there is nothing
933    /// left to arrive, so running out there is a malformation and waiting for
934    /// more would be waiting forever.
935    ///
936    /// [`VarIntError::UnexpectedEnd`]: crate::varint::VarIntError::UnexpectedEnd
937    /// [`KvpError::UnexpectedEnd`]: crate::kvp::KvpError::UnexpectedEnd
938    /// [`KvpError::VarInt`]: crate::kvp::KvpError::VarInt
939    pub fn is_incomplete(&self) -> bool {
940        use crate::kvp::KvpError;
941        use crate::varint::VarIntError;
942        matches!(
943            self,
944            CodecError::UnexpectedEnd
945                | CodecError::VarInt(VarIntError::UnexpectedEnd)
946                | CodecError::Kvp(KvpError::UnexpectedEnd)
947                | CodecError::Kvp(KvpError::VarInt(VarIntError::UnexpectedEnd))
948        )
949    }
950}