systemprompt_cloud/error/
mod.rs1use systemprompt_identifiers::TenantId;
13use thiserror::Error;
14
15mod messages;
16
17pub type CloudResult<T> = Result<T, CloudError>;
18
19#[derive(Debug, Error)]
20#[non_exhaustive]
21pub enum CloudError {
22 #[error("Authentication required.\n\nRun: systemprompt cloud login")]
23 NotAuthenticated,
24
25 #[error("Token expired.\n\nRun: systemprompt cloud login")]
26 TokenExpired,
27
28 #[error("No tenant configured.\n\nRun: systemprompt cloud setup")]
29 TenantNotConfigured,
30
31 #[error("No app configured.\n\nRun: systemprompt cloud setup")]
32 AppNotConfigured,
33
34 #[error(
35 "Profile required: {message}\n\nSet SYSTEMPROMPT_PROFILE or run 'systemprompt cloud \
36 config'"
37 )]
38 ProfileRequired { message: String },
39
40 #[error("Missing profile field: {field}\n\nAdd to your profile:\n{example}")]
41 MissingProfileField { field: String, example: String },
42
43 #[error("JWT decode error")]
44 JwtDecode,
45
46 #[error("Credentials file corrupted.\n\nRun: systemprompt cloud login")]
47 CredentialsCorrupted {
48 #[source]
49 source: serde_json::Error,
50 },
51
52 #[error("Tenants not synced.\n\nRun: systemprompt cloud login")]
53 TenantsNotSynced,
54
55 #[error("Tenants store corrupted.\n\nRun: systemprompt cloud login")]
56 TenantsStoreCorrupted {
57 #[source]
58 source: serde_json::Error,
59 },
60
61 #[error("Tenants store invalid: {message}")]
62 TenantsStoreInvalid { message: String },
63
64 #[error("Tenant '{}' not found.\n\nRun: systemprompt cloud config", tenant_id.as_str())]
65 TenantNotFound { tenant_id: TenantId },
66
67 #[error("API error: {message}")]
68 ApiError { message: String },
69
70 #[error(transparent)]
71 Network(#[from] reqwest::Error),
72
73 #[error(transparent)]
74 Io(#[from] std::io::Error),
75
76 #[error(transparent)]
77 Json(#[from] serde_json::Error),
78
79 #[error("Cloud API validation failed: {message}")]
80 ApiValidationFailed { message: String },
81
82 #[error("Cloud credentials file invalid: {message}")]
83 InvalidCredentials { message: String },
84
85 #[error("Cloud credentials file not found: {path}")]
86 CredentialsFileNotFound { path: String },
87
88 #[error("Credentials not initialized")]
89 CredentialsNotInitialized,
90
91 #[error("Credentials already initialized")]
92 CredentialsAlreadyInitialized,
93
94 #[error(
95 "Session file version mismatch: expected {min}-{max}, got {actual}. Delete {path} and \
96 retry."
97 )]
98 SessionVersionMismatch {
99 min: u32,
100 max: u32,
101 actual: u32,
102 path: String,
103 },
104
105 #[error("OAuth flow failed: {message}")]
106 OAuthFlow { message: String },
107
108 #[error("Checkout flow failed: {message}")]
109 CheckoutFlow { message: String },
110
111 #[error("SSE stream error: {message}")]
112 SseStream { message: String },
113
114 #[error("Provisioning failed: {message}")]
115 ProvisioningFailed { message: String },
116
117 #[error("{message}")]
118 Deploy {
119 message: String,
120 #[source]
121 source: Option<Box<dyn std::error::Error + Send + Sync>>,
122 },
123
124 #[error("{message}")]
125 Dockerfile { message: String },
126
127 #[error("{message}")]
128 Docker {
129 message: String,
130 #[source]
131 source: Option<Box<dyn std::error::Error + Send + Sync>>,
132 },
133
134 #[error("Authentication failed. Please run 'systemprompt cloud login' again.")]
135 Unauthorized,
136
137 #[error("Request failed with status {status}: {body}")]
138 HttpStatus { status: u16, body: String },
139
140 #[error("{message}")]
141 Other { message: String },
142}
143
144impl CloudError {
145 pub fn other(message: impl Into<String>) -> Self {
146 Self::Other {
147 message: message.into(),
148 }
149 }
150
151 pub fn deploy(message: impl Into<String>) -> Self {
152 Self::Deploy {
153 message: message.into(),
154 source: None,
155 }
156 }
157
158 pub fn deploy_with(
159 message: impl Into<String>,
160 source: impl Into<Box<dyn std::error::Error + Send + Sync>>,
161 ) -> Self {
162 Self::Deploy {
163 message: message.into(),
164 source: Some(source.into()),
165 }
166 }
167
168 pub fn dockerfile(message: impl Into<String>) -> Self {
169 Self::Dockerfile {
170 message: message.into(),
171 }
172 }
173
174 pub fn docker(message: impl Into<String>) -> Self {
175 Self::Docker {
176 message: message.into(),
177 source: None,
178 }
179 }
180
181 pub fn docker_with(
182 message: impl Into<String>,
183 source: impl Into<Box<dyn std::error::Error + Send + Sync>>,
184 ) -> Self {
185 Self::Docker {
186 message: message.into(),
187 source: Some(source.into()),
188 }
189 }
190
191 pub const fn is_missing_credentials_file(&self) -> bool {
192 matches!(self, Self::CredentialsFileNotFound { .. })
193 }
194
195 pub const fn is_local_mode_recoverable(&self) -> bool {
196 matches!(
197 self,
198 Self::CredentialsFileNotFound { .. }
199 | Self::TokenExpired
200 | Self::ApiValidationFailed { .. }
201 )
202 }
203}