Skip to main content

sanctum_ai/
error.rs

1use serde::{Deserialize, Serialize};
2use thiserror::Error;
3
4/// Error codes returned by the SanctumAI vault.
5#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
6#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
7pub enum ErrorCode {
8    AuthFailed,
9    AccessDenied,
10    CredentialNotFound,
11    VaultLocked,
12    LeaseExpired,
13    RateLimited,
14    SessionExpired,
15    #[serde(other)]
16    Unknown,
17}
18
19impl std::fmt::Display for ErrorCode {
20    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
21        match self {
22            Self::AuthFailed => write!(f, "AUTH_FAILED"),
23            Self::AccessDenied => write!(f, "ACCESS_DENIED"),
24            Self::CredentialNotFound => write!(f, "CREDENTIAL_NOT_FOUND"),
25            Self::VaultLocked => write!(f, "VAULT_LOCKED"),
26            Self::LeaseExpired => write!(f, "LEASE_EXPIRED"),
27            Self::RateLimited => write!(f, "RATE_LIMITED"),
28            Self::SessionExpired => write!(f, "SESSION_EXPIRED"),
29            Self::Unknown => write!(f, "UNKNOWN"),
30        }
31    }
32}
33
34/// Structured error from the vault.
35#[derive(Debug, Clone, Serialize, Deserialize)]
36pub struct VaultError {
37    pub code: ErrorCode,
38    pub message: String,
39    #[serde(skip_serializing_if = "Option::is_none")]
40    pub detail: Option<String>,
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub suggestion: Option<String>,
43    #[serde(skip_serializing_if = "Option::is_none")]
44    pub docs_url: Option<String>,
45    #[serde(skip_serializing_if = "Option::is_none")]
46    pub context: Option<serde_json::Value>,
47}
48
49impl std::fmt::Display for VaultError {
50    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
51        write!(f, "[{}] {}", self.code, self.message)?;
52        if let Some(ref detail) = self.detail {
53            write!(f, " — {detail}")?;
54        }
55        Ok(())
56    }
57}
58
59/// Top-level SDK error type.
60#[derive(Debug, Error)]
61pub enum SanctumError {
62    #[error("IO error: {0}")]
63    Io(#[from] std::io::Error),
64
65    #[error("JSON error: {0}")]
66    Json(#[from] serde_json::Error),
67
68    #[error("Vault error: {0}")]
69    Vault(Box<VaultError>),
70
71    #[error("Protocol error: {0}")]
72    Protocol(String),
73
74    #[error("Authentication failed: {0}")]
75    Auth(String),
76
77    #[error("Signature error: {0}")]
78    Signature(#[from] ed25519_dalek::SignatureError),
79}
80
81pub type Result<T> = std::result::Result<T, SanctumError>;