Skip to main content

torii_lib/
error.rs

1use thiserror::Error;
2
3#[derive(Error, Debug)]
4pub enum ToriiError {
5    #[error("Git error: {0}")]
6    Git(#[from] git2::Error),
7
8    #[error("IO error: {0}")]
9    Io(#[from] std::io::Error),
10
11    #[error("Repository not found: {0}")]
12    RepositoryNotFound(String),
13
14    #[error("Branch not found: {0}")]
15    #[allow(dead_code)]
16    BranchNotFound(String),
17
18    #[error("Snapshot error: {0}")]
19    Snapshot(String),
20
21    #[error("Mirror error: {0}")]
22    Mirror(String),
23
24    #[error("Serialization error: {0}")]
25    Serialization(#[from] serde_json::Error),
26
27    #[error("Other error: {0}")]
28    Other(#[from] anyhow::Error),
29
30    #[error("Invalid configuration: {0}")]
31    InvalidConfig(String),
32
33    // 0.7.22 introduced precise variants to replace the catch-all
34    // InvalidConfig; the bulk migration (~415 sites) is done. The
35    // remaining InvalidConfig uses are *genuine* configuration errors
36    // (config keys/values, missing user.name/email, config dirs,
37    // policy files). New code should never add InvalidConfig for
38    // network/API/auth/subprocess/fs/repo-state failures.
39
40    /// Networking / HTTP transport failure (DNS, connect, timeout,
41    /// unexpected I/O — *not* a non-2xx response, see PlatformApi).
42    #[error("Network error ({provider}): {message}")]
43    #[allow(dead_code)]
44    Network { provider: String, message: String },
45
46    /// Platform-side rejection — the API returned a non-success
47    /// status with a structured body.
48    #[error("{provider} API {status}: {message}")]
49    #[allow(dead_code)]
50    PlatformApi { provider: String, status: u16, message: String },
51
52    /// Credential / authorisation problem (missing token, expired
53    /// PAT, 401, scope mismatch). Surfaces separately from
54    /// "the config file is malformed".
55    #[error("Auth error ({provider}): {message}")]
56    #[allow(dead_code)]
57    Auth { provider: String, message: String },
58
59    /// The API answered 2xx but the body wasn't what we expected
60    /// (unparseable JSON, missing field, wrong shape). Distinct from
61    /// PlatformApi: the platform didn't *reject* us, it confused us.
62    #[error("Malformed {provider} response: {message}")]
63    MalformedResponse { provider: String, message: String },
64
65    /// An external tool we shell out to (git, gpg, docker, $EDITOR,
66    /// $SHELL, …) could not be spawned, or exited unsuccessfully.
67    #[error("`{tool}` failed: {message}")]
68    Subprocess { tool: String, message: String },
69
70    /// Filesystem operation failure with context (what we were doing
71    /// and on which path). Wraps the raw io::Error message — use
72    /// instead of the bare `Io` variant when context is available.
73    #[error("Filesystem error: {0}")]
74    Fs(String),
75
76    /// The repository is in a state that doesn't allow the requested
77    /// operation (bare repo, detached/unborn HEAD, mid-rebase, …).
78    #[error("Repository state error: {0}")]
79    RepoState(String),
80
81    /// Multi-repo workspace bookkeeping problem (unknown workspace,
82    /// missing member path, malformed workspaces.toml entry).
83    #[error("Workspace error: {0}")]
84    Workspace(String),
85
86    /// The platform (or torii) doesn't support the requested
87    /// operation — capability gaps ("Bitbucket has no log-erase"),
88    /// not-yet-wired surfaces, unsupported platform names. The
89    /// message explains the workaround when one exists.
90    #[error("Not supported: {0}")]
91    Unsupported(String),
92
93    /// The command was invoked incorrectly — missing argument,
94    /// conflicting flags, a path that isn't what the verb expects.
95    /// Message is self-explanatory, no prefix added.
96    #[error("{0}")]
97    Usage(String),
98}
99
100pub type Result<T> = std::result::Result<T, ToriiError>;