Skip to main content

clawdb_client/
error.rs

1use thiserror::Error;
2
3/// All errors that can be returned by the ClawDB Rust SDK.
4#[derive(Debug, Error)]
5pub enum SdkError {
6    #[error("Authentication failed: {0}")]
7    Auth(String),
8
9    #[error("Access denied: {resource}/{action}")]
10    AccessDenied { resource: String, action: String },
11
12    #[error("{entity_type} not found: {entity_id}")]
13    NotFound { entity_type: String, entity_id: String },
14
15    #[error("Rate limited; retry after {retry_after_ms}ms")]
16    RateLimit { retry_after_ms: u64 },
17
18    #[error("Service unavailable: {0}")]
19    Unavailable(String),
20
21    #[error("Request timed out after {timeout_ms}ms")]
22    Timeout { timeout_ms: u64 },
23
24    #[error("Validation error on field `{field}`: {constraint}")]
25    Validation { field: String, constraint: String },
26
27    #[error("Configuration error: {0}")]
28    Config(String),
29
30    #[error("HTTP error {status}: {body}")]
31    Http { status: u16, body: String },
32
33    #[error("JSON error: {0}")]
34    Serialization(#[from] serde_json::Error),
35
36    #[error("Invalid URL: {0}")]
37    InvalidUrl(#[from] url::ParseError),
38
39    #[error("Internal error: {0}")]
40    Internal(String),
41
42    #[cfg(feature = "http")]
43    #[error("Reqwest error: {0}")]
44    Reqwest(#[from] reqwest::Error),
45}
46
47/// Convenience type alias.
48pub type SdkResult<T> = Result<T, SdkError>;
49
50impl SdkError {
51    /// Whether the error is retriable.
52    pub fn is_retriable(&self) -> bool {
53        matches!(self, SdkError::Unavailable(_) | SdkError::RateLimit { .. })
54    }
55
56    /// Maps an HTTP status code and body text to an SdkError.
57    pub fn from_http(status: u16, body: &str) -> Self {
58        match status {
59            401 | 403 => SdkError::Auth(body.to_string()),
60            404 => SdkError::NotFound {
61                entity_type: "entity".into(),
62                entity_id: "unknown".into(),
63            },
64            429 => SdkError::RateLimit { retry_after_ms: 1000 },
65            503 => SdkError::Unavailable(body.to_string()),
66            408 | 504 => SdkError::Timeout { timeout_ms: 30000 },
67            400 | 422 => SdkError::Validation {
68                field: "input".into(),
69                constraint: body.to_string(),
70            },
71            _ => SdkError::Http {
72                status,
73                body: body.to_string(),
74            },
75        }
76    }
77}