Skip to main content

systemprompt_sync/
error.rs

1use thiserror::Error;
2
3#[derive(Debug, Error)]
4pub enum SyncError {
5    #[error("API error {status}: {message}")]
6    ApiError { status: u16, message: String },
7
8    #[error("Unauthorized - run 'systemprompt cloud login'")]
9    Unauthorized,
10
11    #[error("Tenant has no associated app")]
12    TenantNoApp,
13
14    #[error("Must run from project root (with infrastructure/ directory)")]
15    NotProjectRoot,
16
17    #[error("Command failed: {command}")]
18    CommandFailed { command: String },
19
20    #[error("Failed to spawn `{command}`: {source}")]
21    CommandSpawnFailed {
22        command: String,
23        #[source]
24        source: std::io::Error,
25    },
26
27    #[error("Failed to open file {path}: {source}")]
28    FileOpenFailed {
29        path: String,
30        #[source]
31        source: std::io::Error,
32    },
33
34    #[error("Docker login failed")]
35    DockerLoginFailed,
36
37    #[error("Git SHA unavailable")]
38    GitShaUnavailable,
39
40    #[error("Missing configuration: {0}")]
41    MissingConfig(String),
42
43    #[error("Partial import failure after {completed}/{total} items: {message}")]
44    PartialImport {
45        completed: usize,
46        total: usize,
47        message: String,
48    },
49
50    #[error("Unsafe tarball entry rejected: {0}")]
51    TarballUnsafe(String),
52
53    #[error("IO error: {0}")]
54    Io(#[from] std::io::Error),
55
56    #[error("HTTP error: {0}")]
57    Http(#[from] reqwest::Error),
58
59    #[error("JSON error: {0}")]
60    Json(#[from] serde_json::Error),
61
62    #[error("Database error: {0}")]
63    Database(#[from] sqlx::Error),
64
65    #[error("Path error: {0}")]
66    StripPrefix(#[from] std::path::StripPrefixError),
67
68    #[error("Zip error: {0}")]
69    Zip(#[from] zip::result::ZipError),
70}
71
72impl SyncError {
73    pub const fn is_retryable(&self) -> bool {
74        matches!(self, Self::Http(_))
75            || matches!(
76                self,
77                Self::ApiError { status, .. }
78                    if *status == 502 || *status == 503 || *status == 504 || *status == 429
79            )
80    }
81}
82
83pub type SyncResult<T> = Result<T, SyncError>;