Skip to main content

agent_protocols/
error.rs

1use thiserror::Error;
2
3pub type Result<T> = std::result::Result<T, SdkError>;
4
5#[derive(Debug, Error)]
6pub enum SdkError {
7    #[error("invalid agent id: {0}")]
8    InvalidAgentId(String),
9
10    #[error("agent id must start with did:agent:")]
11    InvalidAgentIdPrefix,
12
13    #[error("invalid public key length: expected 32 bytes, got {0}")]
14    InvalidPublicKeyLength(usize),
15
16    #[error("canonical JSON error: {0}")]
17    CanonicalJson(String),
18
19    #[error("JSON error: {0}")]
20    Json(#[from] serde_json::Error),
21
22    #[error("base64url decode error: {0}")]
23    Base64(#[from] base64::DecodeError),
24
25    #[error("Ed25519 error: {0}")]
26    Ed25519(#[from] ed25519_dalek::SignatureError),
27
28    #[error("random generation error: {0}")]
29    Random(String),
30
31    #[error("invalid signature length: expected 64 bytes, got {0}")]
32    InvalidSignatureLength(usize),
33
34    #[error("invalid event hash: expected {expected}, got {actual}")]
35    InvalidEventHash { expected: String, actual: String },
36
37    #[error("invalid event hash length: expected 32 bytes, got {0}")]
38    InvalidEventHashLength(usize),
39
40    #[error("invalid event protocol: expected {expected}, got {actual}")]
41    InvalidEventProtocol { expected: String, actual: String },
42
43    #[error("invalid event type: expected {expected}, got {actual}")]
44    InvalidEventType { expected: String, actual: String },
45
46    #[error("invalid actor: {0}")]
47    InvalidActor(String),
48
49    #[error("timestamp is outside the allowed live-write window")]
50    TimestampOutOfWindow,
51
52    #[error("invalid nonce: {0}")]
53    InvalidNonce(String),
54
55    #[error("nonce must be greater than accepted max nonce {max_nonce}")]
56    NonceNotGreater { max_nonce: u64 },
57
58    #[error("event requires a room_id")]
59    MissingRoomId,
60
61    #[error("room id mismatch: expected {expected}, got {actual}")]
62    RoomIdMismatch { expected: String, actual: String },
63
64    #[error("permission denied")]
65    PermissionDenied,
66
67    #[error("invalid payload: {0}")]
68    InvalidPayload(String),
69
70    #[error("event type is not defined in the room: {0}")]
71    TypeNotDefined(String),
72
73    #[error("event type is disabled in the room: {0}")]
74    TypeDisabled(String),
75
76    #[error("payload does not satisfy the type schema: {0}")]
77    PayloadSchemaViolation(String),
78
79    #[error("type pack cannot be resolved or fails verification: {0}")]
80    PackUnavailable(String),
81
82    #[error("invalid JWT: {0}")]
83    InvalidJwt(String),
84
85    #[error("invalid JWT claim: {0}")]
86    InvalidJwtClaim(&'static str),
87
88    /// A protocol error identified by its Agent Protocols error code.
89    #[error("{code}: {message}")]
90    Protocol { code: &'static str, message: String },
91
92    /// A protocol error with machine-readable error data.
93    #[error("{code}: {message}")]
94    ProtocolWithData {
95        code: &'static str,
96        message: String,
97        data: serde_json::Value,
98    },
99
100    /// A client-side page budget ended before a paginated read completed.
101    #[error("paginated read did not complete within {0} pages")]
102    PageLimitExceeded(usize),
103
104    /// A non-2xx response. `code` and `data` come from the Agent Identity
105    /// error body when the service sent one; `max_seen_nonce` from the
106    /// `Max-Seen-Nonce` header.
107    #[error("HTTP {status}: {body}")]
108    HttpStatus {
109        status: u16,
110        code: Option<String>,
111        data: Option<serde_json::Value>,
112        max_seen_nonce: Option<String>,
113        body: String,
114    },
115
116    #[cfg(feature = "http-client")]
117    #[error("HTTP client error: {0}")]
118    Http(#[from] reqwest::Error),
119}
120
121impl SdkError {
122    /// Builds a [`SdkError::Protocol`] error.
123    pub fn protocol(code: &'static str, message: impl Into<String>) -> Self {
124        Self::Protocol {
125            code,
126            message: message.into(),
127        }
128    }
129
130    pub fn protocol_with_data(
131        code: &'static str,
132        message: impl Into<String>,
133        data: serde_json::Value,
134    ) -> Self {
135        Self::ProtocolWithData {
136            code,
137            message: message.into(),
138            data,
139        }
140    }
141
142    pub fn data(&self) -> Option<&serde_json::Value> {
143        match self {
144            Self::ProtocolWithData { data, .. } => Some(data),
145            Self::HttpStatus { data, .. } => data.as_ref(),
146            _ => None,
147        }
148    }
149
150    /// The Agent Protocols error code this error corresponds to, when there is one.
151    pub fn code(&self) -> Option<&str> {
152        match self {
153            Self::Protocol { code, .. } | Self::ProtocolWithData { code, .. } => Some(code),
154            Self::HttpStatus { code, .. } => code.as_deref(),
155            Self::InvalidSignatureLength(_) | Self::Ed25519(_) => Some("invalid_signature"),
156            Self::InvalidEventHash { .. } | Self::InvalidEventHashLength(_) => {
157                Some("invalid_event_hash")
158            }
159            Self::TimestampOutOfWindow => Some("timestamp_out_of_window"),
160            Self::NonceNotGreater { .. } => Some("nonce_not_greater"),
161            Self::PermissionDenied => Some("permission_denied"),
162            Self::TypeNotDefined(_) => Some("type_not_defined"),
163            Self::TypeDisabled(_) => Some("type_disabled"),
164            Self::PayloadSchemaViolation(_) => Some("payload_schema_violation"),
165            Self::PackUnavailable(_) => Some("pack_unavailable"),
166            Self::InvalidJwt(_) | Self::InvalidJwtClaim(_) => Some("invalid_token"),
167            Self::InvalidActor(_) => Some("invalid_actor"),
168            _ => None,
169        }
170    }
171}