1use crate::{access::AccessError, dto::prelude::*};
2use std::fmt::{self, Display};
3
4#[derive(CandidType, Clone, Debug, Deserialize, Eq, PartialEq, Serialize)]
11pub struct Error {
12 pub code: ErrorCode,
13 pub message: String,
14}
15
16impl Error {
17 #[must_use]
18 pub const fn new(code: ErrorCode, message: String) -> Self {
19 Self { code, message }
20 }
21
22 pub fn conflict(message: impl Into<String>) -> Self {
24 Self::new(ErrorCode::Conflict, message.into())
25 }
26
27 pub fn policy(code: ErrorCode, message: impl Into<String>) -> Self {
29 Self::new(code, message.into())
30 }
31
32 pub fn forbidden(message: impl Into<String>) -> Self {
34 Self::new(ErrorCode::Forbidden, message.into())
35 }
36
37 pub fn internal(message: impl Into<String>) -> Self {
39 Self::new(ErrorCode::Internal, message.into())
40 }
41
42 pub fn invalid(message: impl Into<String>) -> Self {
44 Self::new(ErrorCode::InvalidInput, message.into())
45 }
46
47 #[must_use]
49 pub fn operation_id_required() -> Self {
50 Self::new(
51 ErrorCode::OperationIdRequired,
52 "operation_id is required for this command".to_string(),
53 )
54 }
55
56 pub fn invariant(message: impl Into<String>) -> Self {
58 Self::new(ErrorCode::InvariantViolation, message.into())
59 }
60
61 pub fn exhausted(message: impl Into<String>) -> Self {
63 Self::new(ErrorCode::ResourceExhausted, message.into())
64 }
65
66 pub fn not_found(message: impl Into<String>) -> Self {
68 Self::new(ErrorCode::NotFound, message.into())
69 }
70
71 pub fn unauthorized(message: impl Into<String>) -> Self {
73 Self::new(ErrorCode::Unauthorized, message.into())
74 }
75
76 pub fn unavailable(message: impl Into<String>) -> Self {
78 Self::new(ErrorCode::Unavailable, message.into())
79 }
80
81 pub fn auth_token_expired(message: impl Into<String>) -> Self {
83 Self::new(ErrorCode::AuthTokenExpired, message.into())
84 }
85
86 pub fn auth_proof_pending(message: impl Into<String>) -> Self {
88 Self::new(ErrorCode::AuthProofPending, message.into())
89 }
90
91 #[must_use]
93 pub fn root_data_certificate_unavailable() -> Self {
94 Self::new(
95 ErrorCode::RootDataCertificateUnavailable,
96 "root data certificate unavailable for role-attestation proof retrieval".to_string(),
97 )
98 }
99}
100
101impl Display for Error {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 write!(f, "[{:?}] {}", self.code, self.message)
104 }
105}
106
107impl From<AccessError> for Error {
108 fn from(err: AccessError) -> Self {
109 let kind = err.kind();
110 let message = err.to_string();
111 match kind {
112 crate::access::AccessErrorKind::DelegatedAuthCertExpired => {
113 Self::new(ErrorCode::AuthProofExpired, message)
114 }
115 crate::access::AccessErrorKind::DelegatedAuthTokenExpired => {
116 Self::auth_token_expired(message)
117 }
118 crate::access::AccessErrorKind::Denied => Self::unauthorized(message),
119 }
120 }
121}
122
123#[derive(CandidType, Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize)]
130#[non_exhaustive]
131#[remain::sorted]
132pub enum ErrorCode {
133 AuthMaterialStale,
134 AuthProofExpired,
135 AuthProofPending,
136 AuthTokenExpired,
137 Conflict,
138 Forbidden,
139 Internal,
140 InternalRpcMalformed,
141 InvalidInput,
142 InvariantViolation,
143 NotFound,
144 OperationIdRequired,
145 PolicyInstanceRequiresServiceWithDirectory,
146 PolicyReplicaRequiresServiceWithScaling,
147 PolicyRoleAlreadyRegistered,
148 PolicyShardRequiresServiceWithSharding,
149 PolicySingletonAlreadyRegisteredUnderParent,
150 ResourceExhausted,
151 RootDataCertificateUnavailable,
152 Unauthorized,
153 Unavailable,
154 WasmStoreCapacityExceeded,
155 WasmStoreChunkMissing,
156 WasmStoreHashMismatch,
157 WasmStoreManifestMissing,
158}