atproto_record/errors.rs
1//! Structured error types for AT Protocol record operations.
2//!
3//! This module provides comprehensive error handling for all AT Protocol record operations
4//! using type-safe error enums powered by the `thiserror` library. All errors follow the
5//! project's standardized naming convention for consistent error reporting and debugging.
6//!
7//! ## Error Categories
8//!
9//! ### `VerificationError` (Domain: verification)
10//! Errors related to cryptographic signature creation and verification operations.
11//! Error codes: verification-1 through verification-11
12//!
13//! ### `AturiError` (Domain: aturi)
14//! Errors occurring during AT-URI parsing and validation.
15//! Error codes: aturi-1 through aturi-9
16//!
17//! ### `TidError` (Domain: tid)
18//! Errors occurring during TID (Timestamp Identifier) parsing and decoding.
19//! Error codes: tid-1 through tid-3
20//!
21//! ### `CliError` (Domain: cli)
22//! Command-line interface specific errors for file I/O, argument parsing, and DID validation.
23//! Error codes: cli-1 through cli-10
24//!
25//! ## Error Format
26//!
27//! All errors follow the standardized format:
28//! ```text
29//! error-atproto-record-{domain}-{number} {message}: {details}
30//! ```
31//!
32//! ## Example Usage
33//!
34//! ```ignore
35//! use atproto_record::errors::VerificationError;
36//!
37//! fn verify_signature() -> Result<(), VerificationError> {
38//! // Verification logic
39//! Err(VerificationError::NoSignaturesField)
40//! }
41//! ```
42
43use thiserror::Error;
44
45/// Errors that can occur during record signature creation and verification.
46///
47/// This enum covers all failure modes in the signature lifecycle, from creating
48/// signatures with missing metadata fields to verifying signatures with invalid
49/// cryptographic proofs or serialization failures.
50#[derive(Debug, Error)]
51pub enum VerificationError {
52 /// Error when no signatures field is found in the record.
53 ///
54 /// This error occurs when a record does not contain either a "signatures"
55 /// or "sigs" field, which is required for signature verification.
56 #[error("error-atproto-record-verification-1 No signatures field found in record")]
57 NoSignaturesField,
58
59 /// Error when issuer field is missing from a signature object.
60 ///
61 /// This error occurs when a signature object in the signatures array
62 /// does not contain the required "issuer" field.
63 #[error("error-atproto-record-verification-2 Missing issuer field in signature object")]
64 MissingIssuerField,
65
66 /// Error when signature field is missing from a signature object.
67 ///
68 /// This error occurs when a signature object in the signatures array
69 /// does not contain the required "signature" field.
70 #[error("error-atproto-record-verification-3 Missing signature field in signature object")]
71 MissingSignatureField,
72
73 /// Error when record serialization fails.
74 ///
75 /// This error occurs when the signed record cannot be serialized
76 /// to IPLD CBOR format for signature verification.
77 #[error("error-atproto-record-verification-4 Record serialization failed: {error}")]
78 RecordSerializationFailed {
79 /// The underlying serialization error
80 #[from]
81 error: atproto_dasl::EncodeError,
82 },
83
84 /// Error when signature verification fails.
85 ///
86 /// This error occurs when the cryptographic verification of the
87 /// signature against the signed record fails, indicating the
88 /// signature is invalid for the given data and public key.
89 #[error("error-atproto-record-verification-5 Signature verification failed: {error}")]
90 SignatureVerificationFailed {
91 /// The underlying verification error
92 error: anyhow::Error,
93 },
94
95 /// Error when no valid signature is found for the specified issuer.
96 ///
97 /// This error occurs when none of the signatures in the record
98 /// belong to the specified issuer, or when all signatures from
99 /// the issuer fail verification.
100 #[error("error-atproto-record-verification-6 No valid signature found for issuer: {issuer}")]
101 NoValidSignatureForIssuer {
102 /// The issuer DID for which no valid signature was found
103 issuer: String,
104 },
105
106 /// Error when signature object is not a valid JSON object.
107 ///
108 /// This error occurs when the provided signature object parameter
109 /// is not a JSON object type, which is required for signature creation.
110 #[error("error-atproto-record-verification-7 Signature object must be a JSON object")]
111 InvalidSignatureObjectType,
112
113 /// Error when signature object is missing required fields.
114 ///
115 /// This error occurs when the signature object is missing fields that are
116 /// necessary during signature creation, such as 'issuer'.
117 #[error("error-atproto-record-verification-8 Signature object missing field: {field}")]
118 SignatureObjectMissingField {
119 /// The name of the missing field
120 field: String,
121 },
122
123 /// Error when cryptographic key operations fail.
124 ///
125 /// This error occurs when key-related operations such as signing
126 /// or key parsing fail during signature creation or verification.
127 #[error("error-atproto-record-verification-9 Key operation failed: {error}")]
128 KeyOperationFailed {
129 /// The underlying key operation error
130 #[from]
131 error: atproto_identity::errors::KeyError,
132 },
133
134 /// Error when signature decoding fails.
135 ///
136 /// This error occurs when the multibase-encoded signature cannot
137 /// be decoded, typically due to invalid encoding format.
138 #[error("error-atproto-record-verification-10 Signature decoding failed: {error}")]
139 SignatureDecodingFailed {
140 /// The underlying multibase decoding error
141 error: base64::DecodeError,
142 },
143
144 /// Error when cryptographic signature validation fails.
145 ///
146 /// This error occurs when the cryptographic validation of the signature
147 /// fails, indicating either an invalid signature or mismatched key/data.
148 #[error("error-atproto-record-verification-11 Cryptographic validation failed: {error}")]
149 CryptographicValidationFailed {
150 /// The underlying validation error
151 error: atproto_identity::errors::KeyError,
152 },
153}
154
155/// Errors that can occur during AT-URI parsing and validation.
156///
157/// This enum covers all validation failures when parsing AT-URIs, including
158/// format violations, missing components, and invalid authority types.
159#[derive(Debug, Error)]
160pub enum AturiError {
161 /// Error when AT-URI does not start with the required "at://" prefix.
162 ///
163 /// This error occurs when the input string does not begin with the
164 /// required AT-URI scheme identifier.
165 #[error("error-atproto-record-aturi-1 Invalid AT-URI format: missing 'at://' prefix")]
166 MissingPrefix,
167
168 /// Error when AT-URI ends with a trailing slash.
169 ///
170 /// This error occurs when the AT-URI string ends with a forward slash,
171 /// which is not permitted in valid AT-URI format.
172 #[error("error-atproto-record-aturi-2 Invalid AT-URI format: trailing slash not permitted")]
173 TrailingSlash,
174
175 /// Error when authority component is missing from AT-URI.
176 ///
177 /// This error occurs when the AT-URI does not contain a valid authority
178 /// component after the "at://" prefix.
179 #[error("error-atproto-record-aturi-3 Authority component missing from AT-URI")]
180 AuthorityMissing,
181
182 /// Error when authority is a handle instead of a DID.
183 ///
184 /// This error occurs when the authority component is a handle rather
185 /// than a DID, which is not supported for AT-URI operations.
186 #[error("error-atproto-record-aturi-4 Unsupported authority type: handle not permitted")]
187 HandleNotSupported,
188
189 /// Error when authority component cannot be parsed as a valid DID.
190 ///
191 /// This error occurs when the authority component is not a valid
192 /// handle or DID, or when DID parsing fails.
193 #[error("error-atproto-record-aturi-5 Authority parsing failed: {error}")]
194 AuthorityParsingFailed {
195 /// The underlying parsing error
196 #[from]
197 error: atproto_identity::errors::ResolveError,
198 },
199
200 /// Error when collection (NSID) component is missing from AT-URI.
201 ///
202 /// This error occurs when the AT-URI does not contain a collection
203 /// component after the authority.
204 #[error("error-atproto-record-aturi-6 Collection component missing from AT-URI")]
205 CollectionMissing,
206
207 /// Error when record key component is missing from AT-URI.
208 ///
209 /// This error occurs when the AT-URI does not contain a record key
210 /// component after the collection.
211 #[error("error-atproto-record-aturi-7 Record key component missing from AT-URI")]
212 RecordKeyMissing,
213
214 /// Error when collection (NSID) component is empty in AT-URI.
215 ///
216 /// This error occurs when the AT-URI contains an empty or whitespace-only
217 /// collection component, which is not valid.
218 #[error("error-atproto-record-aturi-8 Collection component cannot be empty")]
219 EmptyCollection,
220
221 /// Error when record key component is empty in AT-URI.
222 ///
223 /// This error occurs when the AT-URI contains an empty or whitespace-only
224 /// record key component, which is not valid.
225 #[error("error-atproto-record-aturi-9 Record key component cannot be empty")]
226 EmptyRecordKey,
227}
228
229/// Errors that can occur during TID (Timestamp Identifier) operations.
230///
231/// This enum covers all validation failures when parsing and decoding TIDs,
232/// including format violations, invalid characters, and encoding errors.
233#[derive(Debug, Error)]
234pub enum TidError {
235 /// Error when TID string length is invalid.
236 ///
237 /// This error occurs when a TID string is not exactly 13 characters long,
238 /// which is required by the TID specification.
239 #[error("error-atproto-record-tid-1 Invalid TID length: expected {expected}, got {actual}")]
240 InvalidLength {
241 /// Expected length (always 13)
242 expected: usize,
243 /// Actual length of the provided string
244 actual: usize,
245 },
246
247 /// Error when TID contains an invalid character.
248 ///
249 /// This error occurs when a TID string contains a character outside the
250 /// base32-sortable character set (234567abcdefghijklmnopqrstuvwxyz).
251 #[error("error-atproto-record-tid-2 Invalid character '{character}' at position {position}")]
252 InvalidCharacter {
253 /// The invalid character
254 character: char,
255 /// Position in the string (0-indexed)
256 position: usize,
257 },
258
259 /// Error when TID format is invalid.
260 ///
261 /// This error occurs when the TID violates structural requirements,
262 /// such as having the top bit set (which must always be 0).
263 #[error("error-atproto-record-tid-3 Invalid TID format: {reason}")]
264 InvalidFormat {
265 /// Reason for the format violation
266 reason: String,
267 },
268}
269
270/// Errors specific to command-line interface operations.
271///
272/// This enum covers failures in CLI argument parsing, file I/O operations,
273/// JSON processing, and DID validation that occur in the binary tools.
274#[derive(Debug, Error)]
275pub enum CliError {
276 /// Occurs when DID method is not supported
277 #[error("error-atproto-record-cli-1 Unsupported DID method: {method}")]
278 UnsupportedDidMethod {
279 /// The unsupported DID method
280 method: String,
281 },
282
283 /// Occurs when DID parsing fails
284 #[error("error-atproto-record-cli-2 Failed to parse DID: {did}")]
285 DidParseFailed {
286 /// The DID that failed to parse
287 did: String,
288 },
289
290 /// Occurs when reading from stdin fails
291 #[error("error-atproto-record-cli-3 Failed to read from stdin")]
292 StdinReadFailed,
293
294 /// Occurs when parsing JSON from stdin fails
295 #[error("error-atproto-record-cli-4 Failed to parse JSON from stdin")]
296 StdinJsonParseFailed,
297
298 /// Occurs when reading a file fails
299 #[error("error-atproto-record-cli-5 Failed to read file: {path}")]
300 FileReadFailed {
301 /// The file path that failed to read
302 path: String,
303 },
304
305 /// Occurs when parsing JSON from a file fails
306 #[error("error-atproto-record-cli-6 Failed to parse JSON from file: {path}")]
307 FileJsonParseFailed {
308 /// The file path containing invalid JSON
309 path: String,
310 },
311
312 /// Occurs when an unexpected argument is provided
313 #[error("error-atproto-record-cli-7 Unexpected argument: {argument}")]
314 UnexpectedArgument {
315 /// The unexpected argument
316 argument: String,
317 },
318
319 /// Occurs when a required value is missing
320 #[error("error-atproto-record-cli-8 Missing required value: {name}")]
321 MissingRequiredValue {
322 /// The name of the missing value
323 name: String,
324 },
325
326 /// Occurs when record serialization to DAG-CBOR fails
327 #[error("error-atproto-record-cli-9 Failed to serialize record to DAG-CBOR: {error}")]
328 RecordSerializationFailed {
329 /// The underlying serialization error
330 error: String,
331 },
332
333 /// Occurs when CID generation fails
334 #[error("error-atproto-record-cli-10 Failed to generate CID: {error}")]
335 CidGenerationFailed {
336 /// The underlying CID generation error
337 error: String,
338 },
339}