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>;