verit_core/error.rs
1use std::fmt;
2
3#[derive(Debug, Clone, PartialEq, Eq)]
4pub enum Error {
5 /// Message does not start with the "VRT" magic family at all — not a
6 /// Veritate message.
7 BadMagic,
8 /// A Veritate message ("VRT" prefix) whose version byte this decoder does
9 /// not implement. `found` is the version digit in the magic; `supported`
10 /// is what this build understands. Guarantees a vN message can never be
11 /// silently misread as vM.
12 UnsupportedVersion { found: u8, supported: u8 },
13 /// The fixed header is structurally invalid for this version: an unknown
14 /// flag bit, or a reserved field that is not zero.
15 MalformedHeader(&'static str),
16 /// Buffer too short for the fixed header or a declared region.
17 Truncated,
18 /// An offset or length points outside the message buffer.
19 OutOfBounds,
20 /// List element index past the end of the list.
21 IndexOutOfBounds,
22 /// A string field holds invalid UTF-8.
23 BadUtf8,
24 /// The (inline) schema bytes are malformed or non-canonical.
25 BadSchema(String),
26 /// A value's type does not match the schema field type (write path),
27 /// or a typed getter was used on a differently-typed field (read path).
28 TypeMismatch { expected: String, got: String },
29 /// Writer and reader schema cannot be resolved (e.g. int narrowing).
30 Incompatible(String),
31 /// A value referenced a field ID that is not in the schema.
32 UnknownFieldId(u16),
33 /// The same field ID appeared twice in one struct value.
34 DuplicateField(u16),
35 /// The same key appeared twice in one map value.
36 DuplicateMapKey,
37 /// A `union` value or wire tag selected a variant index that does not exist.
38 BadUnionTag(u32),
39 /// A dense struct was encoded without one of its (mandatory) fields.
40 MissingField(u16),
41 /// The message's schema id does not match the resolver's writer schema
42 /// (or the inline schema bytes hash to something else).
43 SchemaIdMismatch { message: u128, expected: u128 },
44 /// dump_json needs an inline schema but the message was hash-only.
45 NoInlineSchema,
46 /// Recursion (nested structs/lists) exceeded the safety depth limit — the
47 /// message may contain an offset cycle or hostile nesting.
48 DepthLimitExceeded,
49 /// A bounded read exhausted its traversal budget: the message followed
50 /// offsets that would touch more bytes than the budget allows (an
51 /// amplification guard for untrusted input — see `Budget` / the wire spec §5.2).
52 TraversalBudgetExceeded,
53 /// Message would exceed the 4 GiB u32-offset limit.
54 MessageTooLarge,
55 /// A `.vertc` container file is malformed: bad magic/version, an index
56 /// pointing out of bounds, a misaligned or overlapping record, etc.
57 BadContainer(&'static str),
58 /// A `.verit` file is structurally malformed: bad magic or version, a
59 /// nonzero reserved field, an index entry pointing outside the record
60 /// region, a misaligned offset, and so on.
61 BadFile(&'static str),
62 /// The `.verit` file sets a bit in `required_features` that this build does
63 /// not implement, so it cannot be read correctly (File Format
64 /// Specification §3.1). Unknown *optional* feature bits are ignored, not
65 /// reported here.
66 UnsupportedFileFeature(u32),
67 /// No valid footer was found anywhere in a `.verit` file, so no committed
68 /// state is recoverable — the file was destroyed, not merely torn.
69 NoValidFooter,
70 /// A `.verit` file's index references a schema id its schema section does
71 /// not contain, so the file is not self-contained.
72 MissingSchema(u128),
73 /// Another writer already holds this file's advisory lock. The format
74 /// allows one writer and many readers (File Format Specification §7.3);
75 /// concurrent writers are undefined, so this refuses rather than racing.
76 /// Carries the lock file's path — delete it by hand if a previous writer
77 /// was killed.
78 AlreadyLocked(String),
79 /// A record's bytes do not match the CRC-32 the file stored for it — bit
80 /// rot, or a tampered record. Only reachable on a file written with
81 /// per-record checksums (`OPT_RECORD_CRC`). Names the record's stable id
82 /// rather than its position, since positions shift.
83 ChecksumMismatch {
84 /// The record's stable id.
85 id: u64,
86 /// What the file says the CRC should be.
87 expected: u32,
88 /// What the bytes actually hash to.
89 found: u32,
90 },
91 /// The underlying I/O operation failed. Carried as a string so `Error`
92 /// stays `Clone + PartialEq` (`std::io::Error` is neither).
93 Io(String),
94 /// Internal invariant violation (a bug in this library).
95 Internal(&'static str),
96}
97
98impl fmt::Display for Error {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 match self {
101 Error::BadMagic => write!(f, "not a Veritate message (bad magic)"),
102 Error::UnsupportedVersion { found, supported } => write!(
103 f,
104 "unsupported Veritate wire version: message is v{}, this build implements v{}",
105 *found as char, *supported as char
106 ),
107 Error::MalformedHeader(s) => write!(f, "malformed message header: {s}"),
108 Error::Truncated => write!(f, "message truncated"),
109 Error::OutOfBounds => write!(f, "offset out of bounds"),
110 Error::IndexOutOfBounds => write!(f, "list index out of bounds"),
111 Error::BadUtf8 => write!(f, "string field is not valid UTF-8"),
112 Error::BadSchema(s) => write!(f, "bad schema: {s}"),
113 Error::TypeMismatch { expected, got } => {
114 write!(f, "type mismatch: expected {expected}, got {got}")
115 }
116 Error::Incompatible(s) => write!(f, "schemas incompatible: {s}"),
117 Error::UnknownFieldId(id) => write!(f, "field id {id} not in schema"),
118 Error::DuplicateField(id) => write!(f, "field id {id} set twice"),
119 Error::DuplicateMapKey => write!(f, "the same map key was set twice"),
120 Error::BadUnionTag(t) => write!(f, "union tag {t} is not a valid variant index"),
121 Error::MissingField(id) => {
122 write!(f, "dense struct requires field id {id}, which was not set")
123 }
124 Error::SchemaIdMismatch { message, expected } => write!(
125 f,
126 "schema id mismatch: message has {message:#034x}, expected {expected:#034x}"
127 ),
128 Error::NoInlineSchema => write!(f, "message carries no inline schema"),
129 Error::DepthLimitExceeded => {
130 write!(f, "nesting depth limit exceeded (possible offset cycle)")
131 }
132 Error::TraversalBudgetExceeded => {
133 write!(
134 f,
135 "traversal budget exceeded (possible amplification attack)"
136 )
137 }
138 Error::MessageTooLarge => write!(f, "message exceeds 4 GiB limit"),
139 Error::BadContainer(s) => write!(f, "bad container: {s}"),
140 Error::BadFile(s) => write!(f, "bad .verit file: {s}"),
141 Error::UnsupportedFileFeature(bits) => write!(
142 f,
143 ".verit file requires feature bits {bits:#010x} this build does not implement"
144 ),
145 Error::NoValidFooter => {
146 write!(f, "no valid footer in .verit file (no recoverable commit)")
147 }
148 Error::MissingSchema(id) => write!(
149 f,
150 ".verit file index references schema {id:#034x}, which its schema section does not contain"
151 ),
152 Error::ChecksumMismatch { id, expected, found } => write!(
153 f,
154 "record {id} fails its checksum: file says {expected:#010x}, bytes hash to {found:#010x}"
155 ),
156 Error::AlreadyLocked(p) => write!(
157 f,
158 "another writer holds this .verit file (lock: {p}); \
159 one writer at a time, many readers"
160 ),
161 Error::Io(s) => write!(f, "i/o error: {s}"),
162 Error::Internal(s) => write!(f, "internal error: {s}"),
163 }
164 }
165}
166
167impl std::error::Error for Error {}
168
169impl From<std::io::Error> for Error {
170 fn from(e: std::io::Error) -> Error {
171 Error::Io(e.to_string())
172 }
173}
174
175pub type Result<T> = std::result::Result<T, Error>;