atproto_identity/
errors.rs

1//! # Structured Error Types  
2//!
3//! Comprehensive error handling for AT Protocol identity operations using structured error types
4//! with the `thiserror` library. All errors follow the project convention of prefixed error codes
5//! with descriptive messages.
6//!
7//! ## Error Categories
8//!
9//! - **`WebDIDError`** (web-1 to web-4): Errors specific to `did:web` operations including URL conversion and document fetching
10//! - **`ConfigError`** (config-1 to config-3): Configuration and environment variable related errors
11//! - **`ResolveError`** (resolve-1 to resolve-8): Handle and DID resolution errors including DNS/HTTP failures and conflicts
12//! - **`PLCDIDError`** (plc-1 to plc-2): PLC directory communication and document parsing errors
13//! - **`KeyError`** (key-1 to key-12): Cryptographic key operations including generation, parsing, signing, and validation
14//! - **`StorageError`** (storage-1 to storage-3): Storage operations including cache lock failures and data access errors
15//!
16//! ## Error Format
17//!
18//! All errors use the standardized format: `error-atproto-identity-{domain}-{number} {message}: {details}`
19
20use thiserror::Error;
21
22/// Error types that can occur when working with Web DIDs
23#[derive(Debug, Error)]
24pub enum WebDIDError {
25    /// Occurs when the DID is missing the 'did:web:' prefix
26    #[error("error-atproto-identity-web-1 Invalid DID format: missing 'did:web:' prefix")]
27    InvalidDIDPrefix,
28
29    /// Occurs when the DID is missing a hostname component
30    #[error("error-atproto-identity-web-2 Invalid DID format: missing hostname component")]
31    MissingHostname,
32
33    /// Occurs when the HTTP request to fetch the DID document fails
34    #[error("error-atproto-identity-web-3 HTTP request failed: {url} {error}")]
35    HttpRequestFailed {
36        /// The URL that was requested
37        url: String,
38        /// The underlying HTTP error
39        error: reqwest::Error,
40    },
41
42    /// Occurs when the DID document cannot be parsed from the HTTP response
43    #[error("error-atproto-identity-web-4 Failed to parse DID document: {url} {error}")]
44    DocumentParseFailed {
45        /// The URL that was requested
46        url: String,
47        /// The underlying parse error
48        error: reqwest::Error,
49    },
50}
51
52/// Error types that can occur when working with configuration
53#[derive(Debug, Error)]
54pub enum ConfigError {
55    /// Occurs when a required environment variable is not set
56    #[error("error-atproto-identity-config-1 Required environment variable not found: {name}")]
57    MissingEnvironmentVariable {
58        /// The name of the missing environment variable
59        name: String,
60    },
61
62    /// Occurs when parsing an IP address from nameserver configuration fails
63    #[error("error-atproto-identity-config-2 Unable to parse nameserver IP: {value}")]
64    InvalidNameserverIP {
65        /// The invalid IP address value that could not be parsed
66        value: String,
67    },
68
69    /// Occurs when version information cannot be determined
70    #[error(
71        "error-atproto-identity-config-3 Version information not available: GIT_HASH or CARGO_PKG_VERSION must be set"
72    )]
73    VersionNotAvailable,
74}
75
76/// Error types that can occur when resolving AT Protocol identities
77#[derive(Debug, Error)]
78pub enum ResolveError {
79    /// Occurs when multiple different DIDs are found via DNS TXT record lookup
80    #[error(
81        "error-atproto-identity-resolve-1 Multiple DIDs resolved for handle: expected single DID"
82    )]
83    MultipleDIDsFound,
84
85    /// Occurs when no DIDs are found via either DNS or HTTP resolution methods
86    #[error(
87        "error-atproto-identity-resolve-2 No DIDs resolved for handle: no resolution methods succeeded"
88    )]
89    NoDIDsFound,
90
91    /// Occurs when DNS and HTTP resolution return different DIDs for the same handle
92    #[error(
93        "error-atproto-identity-resolve-3 Conflicting DIDs found for handle: DNS and HTTP resolution returned different results"
94    )]
95    ConflictingDIDsFound,
96
97    /// Occurs when DNS TXT record lookup fails
98    #[error("error-atproto-identity-resolve-4 DNS resolution failed: {error:?}")]
99    DNSResolutionFailed {
100        /// The underlying DNS resolution error
101        error: hickory_resolver::ResolveError,
102    },
103
104    /// Occurs when HTTP request to .well-known/atproto-did endpoint fails
105    #[error("error-atproto-identity-resolve-5 HTTP resolution failed: {error:?}")]
106    HTTPResolutionFailed {
107        /// The underlying HTTP error
108        error: reqwest::Error,
109    },
110
111    /// Occurs when HTTP response from .well-known/atproto-did doesn't start with "did:"
112    #[error(
113        "error-atproto-identity-resolve-6 Invalid HTTP resolution response: expected DID format"
114    )]
115    InvalidHTTPResolutionResponse,
116
117    /// Occurs when input cannot be parsed as a valid handle or DID
118    #[error("error-atproto-identity-resolve-7 Invalid input format: expected valid handle or DID")]
119    InvalidInput,
120
121    /// Occurs when subject resolution results in a handle instead of expected DID
122    #[error("error-atproto-identity-resolve-8 Subject resolved to handle instead of DID")]
123    SubjectResolvedToHandle,
124}
125
126/// Error types that can occur when working with PLC DIDs
127#[derive(Debug, Error)]
128pub enum PLCDIDError {
129    /// Occurs when the HTTP request to the PLC directory fails
130    #[error("error-atproto-identity-plc-1 HTTP request failed: {url} {error}")]
131    HttpRequestFailed {
132        /// The URL that was requested
133        url: String,
134        /// The underlying HTTP error
135        error: reqwest::Error,
136    },
137
138    /// Occurs when the DID document cannot be parsed from the PLC directory response
139    #[error("error-atproto-identity-plc-2 Failed to parse DID document: {url} {error}")]
140    DocumentParseFailed {
141        /// The URL that was requested
142        url: String,
143        /// The underlying parse error
144        error: reqwest::Error,
145    },
146}
147
148/// Error types that can occur when working with cryptographic keys
149#[derive(Debug, Error)]
150pub enum KeyError {
151    /// Occurs when multibase decoding of a key fails
152    #[error("error-atproto-identity-key-1 Error decoding key: {error:?}")]
153    DecodeError {
154        /// The underlying multibase decode error
155        error: multibase::Error,
156    },
157
158    /// Occurs when ECDSA signature parsing fails
159    #[error("error-atproto-identity-key-2 Signature parsing failed: {error:?}")]
160    SignatureError {
161        /// The underlying signature parsing error
162        error: ecdsa::signature::Error,
163    },
164
165    /// Occurs when P-256 key operations fail
166    #[error("error-atproto-identity-key-3 P-256 key operation failed: {error:?}")]
167    P256Error {
168        /// The underlying P-256 key error
169        error: p256::ecdsa::Error,
170    },
171
172    /// Occurs when P-384 key operations fail
173    #[error("error-atproto-identity-key-4 P-384 key operation failed: {error:?}")]
174    P384Error {
175        /// The underlying P-384 key error
176        error: p384::ecdsa::Error,
177    },
178
179    /// Occurs when K-256 key operations fail
180    #[error("error-atproto-identity-key-5 K-256 key operation failed: {error:?}")]
181    K256Error {
182        /// The underlying K-256 key error
183        error: k256::ecdsa::Error,
184    },
185
186    /// Occurs when ECDSA cryptographic operations fail
187    #[error("error-atproto-identity-key-6 ECDSA operation failed: {error:?}")]
188    ECDSAError {
189        /// The underlying ECDSA error
190        error: ecdsa::Error,
191    },
192
193    /// Occurs when secret key parsing or operations fail
194    #[error("error-atproto-identity-key-7 Secret key operation failed: {error:?}")]
195    SecretKeyError {
196        /// The underlying secret key error
197        error: ecdsa::elliptic_curve::Error,
198    },
199
200    /// Occurs when attempting to sign content with a public key instead of a private key
201    #[error("error-atproto-identity-key-8 Private key required for signature")]
202    PrivateKeyRequiredForSignature,
203
204    /// Occurs when attempting to generate a public key directly
205    #[error(
206        "error-atproto-identity-key-9 Public key generation not supported: generate private key instead"
207    )]
208    PublicKeyGenerationNotSupported,
209
210    /// Occurs when the decoded key data is too short to identify the key type
211    #[error("error-atproto-identity-key-10 Unidentified key type: key data too short")]
212    UnidentifiedKeyType,
213
214    /// Occurs when the multibase key type prefix is not recognized
215    #[error("error-atproto-identity-key-11 Invalid multibase key type: {prefix:?}")]
216    InvalidMultibaseKeyType {
217        /// The unrecognized key type prefix
218        prefix: Vec<u8>,
219    },
220
221    /// Occurs when JWK format conversion fails for supported key types
222    #[error("error-atproto-identity-key-12 JWK format conversion failed: {error}")]
223    JWKConversionFailed {
224        /// The underlying conversion error
225        error: String,
226    },
227}
228
229/// Error types that can occur when working with storage operations
230#[derive(Debug, Error)]
231pub enum StorageError {
232    /// Occurs when cache lock acquisition fails during document retrieval operations
233    #[error(
234        "error-atproto-identity-storage-1 Cache lock acquisition failed for get operation: {details}"
235    )]
236    CacheLockFailedGet {
237        /// Details about the lock failure
238        details: String,
239    },
240
241    /// Occurs when cache lock acquisition fails during document storage operations
242    #[error(
243        "error-atproto-identity-storage-2 Cache lock acquisition failed for store operation: {details}"
244    )]
245    CacheLockFailedStore {
246        /// Details about the lock failure
247        details: String,
248    },
249
250    /// Occurs when cache lock acquisition fails during document deletion operations
251    #[error(
252        "error-atproto-identity-storage-3 Cache lock acquisition failed for delete operation: {details}"
253    )]
254    CacheLockFailedDelete {
255        /// Details about the lock failure
256        details: String,
257    },
258}