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    #[cfg(feature = "hickory-dns")]
99    #[error("error-atproto-identity-resolve-4 DNS resolution failed: {error:?}")]
100    DNSResolutionFailed {
101        /// The underlying DNS resolution error
102        error: hickory_resolver::ResolveError,
103    },
104
105    /// Occurs when DNS TXT record lookup fails (generic version for when hickory-dns is not enabled)
106    #[cfg(not(feature = "hickory-dns"))]
107    #[error("error-atproto-identity-resolve-4 DNS resolution failed")]
108    DNSResolutionFailed,
109
110    /// Occurs when HTTP request to .well-known/atproto-did endpoint fails
111    #[error("error-atproto-identity-resolve-5 HTTP resolution failed: {error:?}")]
112    HTTPResolutionFailed {
113        /// The underlying HTTP error
114        error: reqwest::Error,
115    },
116
117    /// Occurs when HTTP response from .well-known/atproto-did doesn't start with "did:"
118    #[error(
119        "error-atproto-identity-resolve-6 Invalid HTTP resolution response: expected DID format"
120    )]
121    InvalidHTTPResolutionResponse,
122
123    /// Occurs when input cannot be parsed as a valid handle or DID
124    #[error("error-atproto-identity-resolve-7 Invalid input format: expected valid handle or DID")]
125    InvalidInput,
126
127    /// Occurs when subject resolution results in a handle instead of expected DID
128    #[error("error-atproto-identity-resolve-8 Subject resolved to handle instead of DID")]
129    SubjectResolvedToHandle,
130}
131
132/// Error types that can occur when working with PLC DIDs
133#[derive(Debug, Error)]
134pub enum PLCDIDError {
135    /// Occurs when the HTTP request to the PLC directory fails
136    #[error("error-atproto-identity-plc-1 HTTP request failed: {url} {error}")]
137    HttpRequestFailed {
138        /// The URL that was requested
139        url: String,
140        /// The underlying HTTP error
141        error: reqwest::Error,
142    },
143
144    /// Occurs when the DID document cannot be parsed from the PLC directory response
145    #[error("error-atproto-identity-plc-2 Failed to parse DID document: {url} {error}")]
146    DocumentParseFailed {
147        /// The URL that was requested
148        url: String,
149        /// The underlying parse error
150        error: reqwest::Error,
151    },
152}
153
154/// Error types that can occur when working with cryptographic keys
155#[derive(Debug, Error)]
156pub enum KeyError {
157    /// Occurs when multibase decoding of a key fails
158    #[error("error-atproto-identity-key-1 Error decoding key: {error:?}")]
159    DecodeError {
160        /// The underlying multibase decode error
161        error: multibase::Error,
162    },
163
164    /// Occurs when ECDSA signature parsing fails
165    #[error("error-atproto-identity-key-2 Signature parsing failed: {error:?}")]
166    SignatureError {
167        /// The underlying signature parsing error
168        error: ecdsa::signature::Error,
169    },
170
171    /// Occurs when P-256 key operations fail
172    #[error("error-atproto-identity-key-3 P-256 key operation failed: {error:?}")]
173    P256Error {
174        /// The underlying P-256 key error
175        error: p256::ecdsa::Error,
176    },
177
178    /// Occurs when P-384 key operations fail
179    #[error("error-atproto-identity-key-4 P-384 key operation failed: {error:?}")]
180    P384Error {
181        /// The underlying P-384 key error
182        error: p384::ecdsa::Error,
183    },
184
185    /// Occurs when K-256 key operations fail
186    #[error("error-atproto-identity-key-5 K-256 key operation failed: {error:?}")]
187    K256Error {
188        /// The underlying K-256 key error
189        error: k256::ecdsa::Error,
190    },
191
192    /// Occurs when ECDSA cryptographic operations fail
193    #[error("error-atproto-identity-key-6 ECDSA operation failed: {error:?}")]
194    ECDSAError {
195        /// The underlying ECDSA error
196        error: ecdsa::Error,
197    },
198
199    /// Occurs when secret key parsing or operations fail
200    #[error("error-atproto-identity-key-7 Secret key operation failed: {error:?}")]
201    SecretKeyError {
202        /// The underlying secret key error
203        error: ecdsa::elliptic_curve::Error,
204    },
205
206    /// Occurs when attempting to sign content with a public key instead of a private key
207    #[error("error-atproto-identity-key-8 Private key required for signature")]
208    PrivateKeyRequiredForSignature,
209
210    /// Occurs when attempting to generate a public key directly
211    #[error(
212        "error-atproto-identity-key-9 Public key generation not supported: generate private key instead"
213    )]
214    PublicKeyGenerationNotSupported,
215
216    /// Occurs when the decoded key data is too short to identify the key type
217    #[error("error-atproto-identity-key-10 Unidentified key type: key data too short")]
218    UnidentifiedKeyType,
219
220    /// Occurs when the multibase key type prefix is not recognized
221    #[error("error-atproto-identity-key-11 Invalid multibase key type: {prefix:?}")]
222    InvalidMultibaseKeyType {
223        /// The unrecognized key type prefix
224        prefix: Vec<u8>,
225    },
226
227    /// Occurs when JWK format conversion fails for supported key types
228    #[error("error-atproto-identity-key-12 JWK format conversion failed: {error}")]
229    JWKConversionFailed {
230        /// The underlying conversion error
231        error: String,
232    },
233}
234
235/// Error types that can occur when working with storage operations
236#[derive(Debug, Error)]
237pub enum StorageError {
238    /// Occurs when cache lock acquisition fails during document retrieval operations
239    #[error(
240        "error-atproto-identity-storage-1 Cache lock acquisition failed for get operation: {details}"
241    )]
242    CacheLockFailedGet {
243        /// Details about the lock failure
244        details: String,
245    },
246
247    /// Occurs when cache lock acquisition fails during document storage operations
248    #[error(
249        "error-atproto-identity-storage-2 Cache lock acquisition failed for store operation: {details}"
250    )]
251    CacheLockFailedStore {
252        /// Details about the lock failure
253        details: String,
254    },
255
256    /// Occurs when cache lock acquisition fails during document deletion operations
257    #[error(
258        "error-atproto-identity-storage-3 Cache lock acquisition failed for delete operation: {details}"
259    )]
260    CacheLockFailedDelete {
261        /// Details about the lock failure
262        details: String,
263    },
264}