A decentralized event management and credentialing system built on atproto.
at main 277 lines 8.5 kB view raw
1//! Core error types for the Acudo application. 2//! 3//! This module provides the main error hierarchy and shared error types used 4//! throughout the application. All error strings follow the standardized format: 5//! 6//! ```text 7//! error-acudo-<domain>-<number> <message>: <details> 8//! ``` 9//! 10//! ## Error Domain Allocation 11//! 12//! To ensure globally unique error identifiers, domains are allocated as follows: 13//! - `config`: 1-99 - Configuration and environment variable errors 14//! - `http`: 100-199 - HTTP layer and web server errors 15//! - `storage`: 200-299 - Database and storage errors 16//! - `auth`: 300-399 - Authentication and authorization errors 17//! - `event`: 400-499 - Event management and AT Protocol errors 18//! - `identity`: 500-599 - DID resolution and identity errors 19//! - `oauth`: 600-699 - OAuth flow and session errors 20 21use std::net::AddrParseError; 22use thiserror::Error; 23 24/// Core application errors that can occur across multiple domains. 25/// 26/// This enum serves as the main error type for the application, aggregating 27/// all domain-specific errors into a single hierarchy. 28#[derive(Debug, Error)] 29pub enum AcudoError { 30 /// Configuration-related errors (domain: config, range: 1-99) 31 #[error(transparent)] 32 Config(#[from] ConfigError), 33 34 /// HTTP layer errors (domain: http, range: 100-199) 35 #[error(transparent)] 36 Http(#[from] HttpError), 37 38 /// Storage and database errors (domain: storage, range: 200-299) 39 #[error(transparent)] 40 Storage(#[from] StorageError), 41 42 /// Event management errors (domain: event, range: 400-499) 43 #[error(transparent)] 44 Event(#[from] EventError), 45 46 /// Identity resolution errors (domain: identity, range: 500-599) 47 #[error(transparent)] 48 Identity(#[from] IdentityError), 49 50 /// OAuth and authentication errors (domain: oauth, range: 600-699) 51 #[error(transparent)] 52 OAuth(#[from] OAuthError), 53} 54 55/// Configuration validation and environment variable errors. 56/// 57/// Error domain: `config` (numbers 1-99) 58#[derive(Error, Debug)] 59pub enum ConfigError { 60 #[error("error-acudo-config-1 Required environment variable not set: {var_name}")] 61 EnvVarRequired { var_name: String }, 62 63 #[error("error-acudo-config-2 Failed to parse port: {source}")] 64 PortParsingFailed { 65 #[source] 66 source: std::num::ParseIntError, 67 }, 68 69 #[error("error-acudo-config-3 Failed to parse nameserver '{nameserver}': {source}")] 70 NameserverParsingFailed { 71 nameserver: String, 72 #[source] 73 source: AddrParseError, 74 }, 75 76 #[error("error-acudo-config-4 No signing keys provided")] 77 EmptySigningKeys, 78 79 #[error("error-acudo-config-5 Missing event AT-URI")] 80 MissingEventAturi, 81 82 #[error("error-acudo-config-6 Invalid event AT-URI format: {aturi}")] 83 InvalidEventAturi { aturi: String }, 84 85 #[error("error-acudo-config-7 Missing issuer DID")] 86 MissingIssuerDid, 87 88 #[error("error-acudo-config-8 Invalid issuer DID format: {did}")] 89 InvalidIssuerDid { did: String }, 90 91 #[error("error-acudo-config-9 Version not set")] 92 VersionNotSet, 93 94 #[error("error-acudo-config-10 Invalid HTTP configuration: {details}")] 95 InvalidHttpConfig { details: String }, 96 97 #[error("error-acudo-config-11 Invalid key format: {details}")] 98 InvalidKeyFormat { details: String }, 99 100 #[error("error-acudo-config-12 Version not available")] 101 VersionNotAvailable, 102 103 #[error("error-acudo-config-13 Invalid port number: {port}")] 104 InvalidPortNumber { port: String }, 105 106 #[error("error-acudo-config-14 Invalid IP address: {address}")] 107 InvalidIpAddress { address: String }, 108 109 #[error("error-acudo-config-15 Invalid timeout value: {value}")] 110 InvalidTimeout { value: String }, 111 112 #[error("error-acudo-config-16 Invalid AT URI: {uri}")] 113 InvalidAtUri { uri: String }, 114 115 #[error("error-acudo-config-17 Invalid OAuth backend: {backend}")] 116 InvalidOAuthBackend { backend: String }, 117 118 #[error("error-acudo-config-18 Invalid DID: {did}")] 119 InvalidDid { did: String }, 120} 121 122/// HTTP layer and web server errors. 123/// 124/// Error domain: `http` (numbers 100-199) 125#[derive(Debug, Error)] 126pub enum HttpError { 127 #[error("error-acudo-http-100 Unhandled web error: {source}")] 128 Unhandled { 129 #[source] 130 source: anyhow::Error, 131 }, 132 133 #[error("error-acudo-http-101 Request validation failed: {details}")] 134 RequestValidation { details: String }, 135 136 #[error("error-acudo-http-102 Authentication required")] 137 AuthenticationRequired, 138 139 #[error("error-acudo-http-103 Forbidden access to resource")] 140 Forbidden, 141 142 #[error("error-acudo-http-104 Resource not found")] 143 NotFound, 144} 145 146/// Storage and database operation errors. 147/// 148/// Error domain: `storage` (numbers 200-299) 149#[derive(Debug, Error)] 150pub enum StorageError { 151 #[error("error-acudo-storage-200 Database connection failed: {source}")] 152 ConnectionFailed { 153 #[source] 154 source: sqlx::Error, 155 }, 156 157 #[error("error-acudo-storage-201 Transaction failed: {source}")] 158 TransactionFailed { 159 #[source] 160 source: sqlx::Error, 161 }, 162 163 #[error("error-acudo-storage-202 Query execution failed: {source}")] 164 QueryFailed { 165 #[source] 166 source: sqlx::Error, 167 }, 168 169 #[error("error-acudo-storage-203 Record not found: {record_type}")] 170 RecordNotFound { record_type: String }, 171 172 #[error("error-acudo-storage-204 Invalid input data: {details}")] 173 InvalidInput { details: String }, 174 175 #[error("error-acudo-storage-205 Serialization failed: {source}")] 176 SerializationFailed { 177 #[source] 178 source: anyhow::Error, 179 }, 180} 181 182/// Event management and AT Protocol record errors. 183/// 184/// Error domain: `event` (numbers 400-499) 185#[derive(Debug, Error)] 186pub enum EventError { 187 #[error("error-acudo-event-400 Invalid AT URI format: {uri}")] 188 InvalidAtUri { uri: String }, 189 190 #[error("error-acudo-event-401 AT URI must have 3 parts (repo/collection/rkey): {uri}")] 191 MalformedAtUri { uri: String }, 192 193 #[error("error-acudo-event-402 Failed to fetch AT Protocol record: {source}")] 194 RecordFetchFailed { 195 #[source] 196 source: anyhow::Error, 197 }, 198 199 #[error("error-acudo-event-403 Failed to parse event record: {source}")] 200 RecordParseFailed { 201 #[source] 202 source: serde_json::Error, 203 }, 204 205 #[error("error-acudo-event-404 No PDS service endpoint found in DID document: {did}")] 206 NoPdsEndpoint { did: String }, 207 208 #[error("error-acudo-event-405 Identity resolution failed for DID {did}: {source}")] 209 IdentityResolution { 210 did: String, 211 #[source] 212 source: anyhow::Error, 213 }, 214 215 #[error("error-acudo-event-406 Failed to fetch record from {uri}: {source}")] 216 RecordFetch { 217 uri: String, 218 #[source] 219 source: anyhow::Error, 220 }, 221 222 #[error("error-acudo-event-407 Failed to parse event record from {uri}: {source}")] 223 EventParsing { 224 uri: String, 225 #[source] 226 source: anyhow::Error, 227 }, 228 229 #[error("error-acudo-event-408 Record not found at {uri}: {details}")] 230 RecordNotFound { uri: String, details: String }, 231} 232 233/// Identity resolution and DID processing errors. 234/// 235/// Error domain: `identity` (numbers 500-599) 236#[derive(Debug, Error)] 237pub enum IdentityError { 238 #[error("error-acudo-identity-500 Failed to resolve DID: {did}")] 239 ResolutionFailed { 240 did: String, 241 #[source] 242 source: anyhow::Error, 243 }, 244 245 #[error("error-acudo-identity-501 Invalid DID format: {did}")] 246 InvalidDidFormat { did: String }, 247 248 #[error("error-acudo-identity-502 DID document missing required service: {service_type}")] 249 MissingService { service_type: String }, 250} 251 252/// OAuth flow and session management errors. 253/// 254/// Error domain: `oauth` (numbers 600-699) 255#[derive(Debug, Error)] 256pub enum OAuthError { 257 #[error("error-acudo-oauth-600 OAuth state cannot be empty")] 258 EmptyState, 259 260 #[error("error-acudo-oauth-601 Issuer cannot be empty")] 261 EmptyIssuer, 262 263 #[error("error-acudo-oauth-602 DID cannot be empty")] 264 EmptyDid, 265 266 #[error("error-acudo-oauth-603 Session chain cannot be empty")] 267 EmptySessionChain, 268 269 #[error("error-acudo-oauth-604 Access token cannot be empty")] 270 EmptyAccessToken, 271 272 #[error("error-acudo-oauth-605 OAuth request not found: {state}")] 273 RequestNotFound { state: String }, 274 275 #[error("error-acudo-oauth-606 OAuth session not found: {session_chain}")] 276 SessionNotFound { session_chain: String }, 277}