Skip to main content

ts_wire/
error.rs

1// Copyright (c) 2026 LightSeek Foundation
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21//! Decode errors.
22
23/// A message that does not match the schema, or is not valid msgpack.
24#[derive(Debug, thiserror::Error)]
25pub enum Error {
26    /// The input ended inside a value.
27    #[error("input truncated at offset {offset}: {needed} more bytes needed")]
28    Truncated {
29        /// Byte offset in the primary frame where the value started.
30        offset: usize,
31        /// Bytes missing past the end of the frame.
32        needed: usize,
33    },
34    /// A value of a different msgpack type than the schema allows.
35    #[error("expected {expected}, found {found} at offset {offset}")]
36    Type {
37        /// What the schema allows here.
38        expected: &'static str,
39        /// The msgpack type found.
40        found: &'static str,
41        /// Byte offset in the primary frame.
42        offset: usize,
43    },
44    /// An integer outside the range of the schema's type.
45    #[error("integer {value} out of range for {target}")]
46    IntRange {
47        /// The decoded integer.
48        value: i128,
49        /// The schema type.
50        target: &'static str,
51    },
52    /// A string that is not valid UTF-8.
53    #[error("invalid UTF-8 string at offset {offset}")]
54    Utf8 {
55        /// Byte offset in the primary frame.
56        offset: usize,
57    },
58    /// A tagged struct whose tag names a different message type.
59    #[error("wrong message tag: expected `{expected}`, found `{found}`")]
60    Tag {
61        /// The tag of the type being decoded.
62        expected: &'static str,
63        /// The tag on the wire.
64        found: String,
65    },
66    /// A struct without a value for a field that has no default.
67    #[error("missing required field `{0}`")]
68    MissingField(&'static str),
69    /// Bytes left in the primary frame after the top-level value.
70    #[error("{0} trailing bytes after the message")]
71    TrailingBytes(usize),
72    /// A value the schema rejects for a reason other than its type.
73    #[error("{0}")]
74    Invalid(String),
75    /// An error inside a named field, kept with the field name for context.
76    #[error("field `{field}`: {source}")]
77    Field {
78        /// The field being decoded.
79        field: &'static str,
80        /// The underlying error.
81        #[source]
82        source: Box<Error>,
83    },
84}
85
86impl Error {
87    /// Attach the name of the field being decoded.
88    pub fn in_field(self, field: &'static str) -> Self {
89        Error::Field {
90            field,
91            source: Box::new(self),
92        }
93    }
94}
95
96/// Result alias for decoding.
97pub type Result<T> = std::result::Result<T, Error>;