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`**: Errors specific to `did:web` operations including URL conversion and document fetching
10//! - **`ConfigError`**: Configuration and environment variable related errors
11//! - **`ResolveError`**: Handle and DID resolution errors including DNS/HTTP failures and conflicts
12//! - **`PLCDIDError`**: PLC directory communication and document parsing errors
13//!
14//! ## Error Format
15//!
16//! All errors use the standardized format: `error-{domain}-{number} {message}: {details}`
17
18use thiserror::Error;
19
20/// Error types that can occur when working with Web DIDs
21#[derive(Debug, Error)]
22pub enum WebDIDError {
23    /// Occurs when the DID is missing the 'did:web:' prefix
24    #[error("error-atproto-identity-web-1 Invalid DID format: missing 'did:web:' prefix")]
25    InvalidDIDPrefix,
26
27    /// Occurs when the DID is missing a hostname component
28    #[error("error-atproto-identity-web-2 Invalid DID format: missing hostname component")]
29    MissingHostname,
30
31    /// Occurs when the HTTP request to fetch the DID document fails
32    #[error("error-atproto-identity-web-3 HTTP request failed: {url} {error}")]
33    HttpRequestFailed {
34        /// The URL that was requested
35        url: String,
36        /// The underlying HTTP error
37        error: reqwest::Error,
38    },
39
40    /// Occurs when the DID document cannot be parsed from the HTTP response
41    #[error("error-atproto-identity-web-4 Failed to parse DID document: {url} {error}")]
42    DocumentParseFailed {
43        /// The URL that was requested
44        url: String,
45        /// The underlying parse error
46        error: reqwest::Error,
47    },
48}
49
50/// Error types that can occur when working with configuration
51#[derive(Debug, Error)]
52pub enum ConfigError {
53    /// Occurs when a required environment variable is not set
54    #[error("error-atproto-identity-config-1 Required environment variable not found: {name}")]
55    MissingEnvironmentVariable {
56        /// The name of the missing environment variable
57        name: String,
58    },
59
60    /// Occurs when parsing an IP address from nameserver configuration fails
61    #[error("error-atproto-identity-config-2 Unable to parse nameserver IP: {value}")]
62    InvalidNameserverIP {
63        /// The invalid IP address value that could not be parsed
64        value: String,
65    },
66
67    /// Occurs when version information cannot be determined
68    #[error("error-atproto-identity-config-3 Version information not available: GIT_HASH or CARGO_PKG_VERSION must be set")]
69    VersionNotAvailable,
70}
71
72/// Error types that can occur when resolving AT Protocol identities
73#[derive(Debug, Error)]
74pub enum ResolveError {
75    /// Occurs when multiple different DIDs are found via DNS TXT record lookup
76    #[error("error-atproto-identity-resolve-1 Multiple DIDs resolved for method")]
77    MultipleDIDsFound,
78
79    /// Occurs when no DIDs are found via either DNS or HTTP resolution methods
80    #[error("error-atproto-identity-resolve-2 No DIDs resolved for method")]
81    NoDIDsFound,
82
83    /// Occurs when DNS and HTTP resolution return different DIDs for the same handle
84    #[error("error-atproto-identity-resolve-3 Conflicting DIDs found for method")]
85    ConflictingDIDsFound,
86
87    /// Occurs when DNS TXT record lookup fails
88    #[error("error-atproto-identity-resolve-4 DNS resolution failed: {0:?}")]
89    DNSResolutionFailed(hickory_resolver::ResolveError),
90
91    /// Occurs when HTTP request to .well-known/atproto-did endpoint fails
92    #[error("error-atproto-identity-resolve-5 HTTP resolution failed: {0:?}")]
93    HTTPResolutionFailed(reqwest::Error),
94
95    /// Occurs when HTTP response from .well-known/atproto-did doesn't start with "did:"
96    #[error("error-atproto-identity-resolve-6 Invalid HTTP resolution response")]
97    InvalidHTTPResolutionResponse,
98
99    /// Occurs when input cannot be parsed as a valid handle or DID
100    #[error("error-atproto-identity-resolve-7 Invalid input")]
101    InvalidInput,
102}
103
104/// Error types that can occur when working with PLC DIDs
105#[derive(Debug, Error)]
106pub enum PLCDIDError {
107    /// Occurs when the HTTP request to the PLC directory fails
108    #[error("error-atproto-identity-plc-1 HTTP request failed: {url} {error}")]
109    HttpRequestFailed {
110        /// The URL that was requested
111        url: String,
112        /// The underlying HTTP error
113        error: reqwest::Error,
114    },
115
116    /// Occurs when the DID document cannot be parsed from the PLC directory response
117    #[error("error-atproto-identity-plc-2 Failed to parse DID document: {url} {error}")]
118    DocumentParseFailed {
119        /// The URL that was requested
120        url: String,
121        /// The underlying parse error
122        error: reqwest::Error,
123    },
124}
125
126/// Error types that can occur when working with cryptographic keys
127#[derive(Debug, Error)]
128pub enum KeyError {
129    /// Occurs when multibase decoding of a key fails
130    #[error("error-atproto-identity-key-1 Error decoding key: {0:?}")]
131    DecodeError(multibase::Error),
132
133    /// Occurs when a key cannot be identified or is in an invalid format
134    #[error("error-atproto-identity-key-2 Invalid key: {0:?}")]
135    InvalidKey(anyhow::Error),
136
137    /// Occurs when ECDSA signature parsing fails
138    #[error("error-atproto-identity-key-3 Signature parsing failed: {0:?}")]
139    SignatureError(ecdsa::signature::Error),
140
141    /// Occurs when P-256 key operations fail
142    #[error("error-atproto-identity-key-4 P256 Error: {0:?}")]
143    P256Error(p256::ecdsa::Error),
144
145    /// Occurs when K-256 key operations fail
146    #[error("error-atproto-identity-key-5 K256 Error: {0:?}")]
147    K256Error(k256::ecdsa::Error),
148
149    /// Occurs when ECDSA cryptographic operations fail
150    #[error("error-atproto-identity-key-6 ECDSA Error: {0:?}")]
151    ECDSAError(ecdsa::Error),
152
153    /// Occurs when secret key parsing or operations fail
154    #[error("error-atproto-identity-key-7 Secret Key Error: {0:?}")]
155    SecretKeyError(ecdsa::elliptic_curve::Error),
156
157    /// Occurs when attempting to sign content with a public key instead of a private key
158    #[error("error-atproto-identity-key-8 Private key required for signature")]
159    PrivateKeyRequiredForSignature,
160}