pub enum KopiaError {
Spawn {
binary: String,
source: Error,
},
NonZeroExit {
args: String,
code: Option<i32>,
class: KopiaErrorClass,
stderr_tail: String,
},
Json {
context: String,
source: Error,
},
EmptyOutput {
context: String,
stderr_tail: String,
},
Timeout {
args: String,
seconds: u64,
},
}Expand description
Errors produced while invoking kopia or parsing its --json output.
Each variant’s Display is actionable — it names the operation, the failure,
and (for non-zero exits) the error class plus the stderr tail — so it can be
dropped straight into a status.failure block (ADR §4.10):
use kopiur_kopia::{KopiaError, KopiaErrorClass};
let err = KopiaError::NonZeroExit {
args: "snapshot create".into(),
code: Some(1),
class: KopiaErrorClass::Locked,
stderr_tail: "repository is locked by another process".into(),
};
assert_eq!(
err.to_string(),
"kopia `snapshot create` failed (exit code 1, class Locked): \
repository is locked by another process",
);
// The class drives the retry decision; the stderr tail is recoverable.
assert_eq!(err.class(), KopiaErrorClass::Locked);
assert!(err.class().is_retryable());
assert_eq!(err.stderr_tail(), Some("repository is locked by another process"));
// A timeout names the args and elapsed seconds, and maps to a retryable class.
let to = KopiaError::Timeout { args: "maintenance run --full".into(), seconds: 3600 };
assert_eq!(to.to_string(), "kopia `maintenance run --full` timed out after 3600s");
assert_eq!(to.class(), KopiaErrorClass::RepositoryUnavailable);Variants§
Spawn
The kopia binary could not be spawned at all (missing binary, not executable, fork failure). Carries the OS error.
NonZeroExit
kopia ran but exited with a non-zero status. Carries everything needed
to build a status.failure block.
Display renders a clean exit code (no Some(1) Debug leak) and a
humanized stderr extract (progress noise dropped, volatile temp-path
fragments stripped) — this is what reaches Warning Events,
status.failure.message, and logs. The full raw tail is preserved in the
stderr_tail field (surfaced via status.failure.stderrTail) for
debugging; read it with stderr_tail.
Fields
args: StringThe subcommand + args that were run (for diagnostics; secrets are passed via env, never argv).
class: KopiaErrorClassBest-effort error classification from stderr.
stderr_tail: StringThe last STDERR_TAIL_LINES lines of stderr, joined by newlines.
Json
kopia exited 0 (or produced output) but the JSON could not be parsed into the expected type — usually a kopia version skew.
Fields
EmptyOutput
We expected a JSON object/array on stdout but found none (kopia printed only progress / nothing) even though it exited 0.
stderr_tail is what makes this diagnosable. Without it the variant
carried neither a reason nor an exit code, so a kopia that exited
cleanly and explained itself on stderr was indistinguishable from a
kopia that said nothing at all — the whole of #351.
Fields
Timeout
The operation exceeded its configured timeout and was killed.
Implementations§
Source§impl KopiaError
impl KopiaError
Sourcepub fn class(&self) -> KopiaErrorClass
pub fn class(&self) -> KopiaErrorClass
The error class for this error, for retry decisions and metrics. Spawn, JSON-parse, empty-output, and timeout errors map to a fixed class; non-zero exits carry their own classification.
Sourcepub fn stderr_tail(&self) -> Option<&str>
pub fn stderr_tail(&self) -> Option<&str>
The trailing stderr lines, if this error captured any.
Trait Implementations§
Source§impl Debug for KopiaError
impl Debug for KopiaError
Source§impl Display for KopiaError
impl Display for KopiaError
Source§impl Error for KopiaError
impl Error for KopiaError
Source§fn source(&self) -> Option<&(dyn Error + 'static)>
fn source(&self) -> Option<&(dyn Error + 'static)>
1.0.0 · Source§fn description(&self) -> &str
fn description(&self) -> &str
use the Display impl or to_string()