Skip to main content

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}