Skip to main content

Error

Enum Error 

Source
#[non_exhaustive]
pub enum Error {
Show 13 variants Spawn { program: String, source: Error, }, NotFound { program: String, searched: Option<String>, }, CassetteMiss { program: String, }, Exit { program: String, code: i32, stdout: String, stderr: String, }, Timeout { program: String, timeout: Duration, stdout: String, stderr: String, }, OutputTooLarge { program: String, line_limit: Option<usize>, byte_limit: Option<usize>, total_lines: usize, total_bytes: usize, }, NotReady { program: String, timeout: Duration, }, Parse { program: String, message: String, }, Unsupported { operation: String, }, Cancelled { program: String, }, Signalled { program: String, signal: Option<i32>, stdout: String, stderr: String, }, Stdin { program: String, source: Error, }, Io(Error),
}
Expand description

Errors produced when launching or running a child process.

Spawn failures, a non-zero exit (Exit), timeouts, and IO errors fold into one structured enum, so callers can pattern-match on the failure mode instead of parsing strings.

Debug is manual, not derived (L22): the Exit variant carries both captured streams in full, and a derived Debug would dump them — potentially multi-MiB — into a {e:?} log line or an .unwrap() panic message. The manual impl bounds each stream to a 200-byte preview (mirroring the Display tail cap) and redacts NotFound’s searched (the PATH env value) to a directory count, honoring the crate’s “never log environment values” rule. The exact streams remain reachable via the public fields.

Variants (Non-exhaustive)§

This enum is marked as non-exhaustive
Non-exhaustive enums could have additional variants added in future. Therefore, when matching against variants of non-exhaustive enums, an extra wildcard arm must be added to account for any future variants.
§

Spawn

The child process could not be started (binary not found, permission denied, …).

Fields

§program: String

The program we tried to launch.

§source: Error

The underlying OS error.

§

NotFound

The program could not be located, so no child was ever started — it is not installed, not on PATH, or the given path does not resolve to an executable. The single representation of “program not found”: the launch path routes every such failure here regardless of how the program was named (bare name vs path) or platform (D11), so a caller matches one variant and is_not_found classifies it.

Distinct from Spawn, which covers OS-level failures once the program is located (permission denied, busy, a bad working directory, a .cmd/.bat on Windows that needs cmd.exe, etc.) — those are not is_not_found.

The searched cause is structured: Some(dirs) when a bare name was looked up against PATH (the directories searched), None when the program was given as a path or PATH was customized (no PATH search applied, so there are no directories to name).

The Display message intentionally omits searchedPATH is an environment value and must never appear in logs per the crate’s security policy. Access searched directly for a diagnostic. The message says “on PATH” only when a PATH search actually happened (searched is Some); a path-form or customized-PATH program reads simply “not found”.

Fields

§program: String

The program name that was looked up.

§searched: Option<String>

The PATH directories searched, joined by the platform separator (: on Unix, ; on Windows) — Some for a bare-name PATH lookup (empty string when PATH is unset), None when no PATH search applied (a path-form program, or a customized PATH). Not included in Display; use it directly when building a user-facing diagnostic.

§

CassetteMiss

A cassette replay found no recording matching the invocation — a stale or incomplete cassette, not a missing program (F7). Kept distinct from Spawn / NotFound so a wrapper that treats “tool not installed” as an optional dependency does not silently swallow a stale cassette as an absent tool.

is_not_found returns false for this variant.

Fields

§program: String

The program whose invocation found no recording.

§

Exit

The process ran to completion but exited with a non-zero status.

Produced by the ensure_success helpers; the raw exit code is otherwise reported without erroring (a non-zero exit is not inherently a failure).

Both captured streams are carried in full: git/jj write decisive diagnostics to stdout on failure (CONFLICT (content): …, nothing to commit, working tree clean), so a caller building a user-facing message wants stdout as a fallback when stderr is empty — see diagnostic. Consumers also classify on these fields (grep for a marker, parse a sub-code), so they are never truncated before the caller sees them; only the Display message below is bounded.

The one-line Display message appends the last non-empty line of diagnostic, capped at 200 bytes — `git` exited with code 2: fatal: boom — actionable in a log line without dumping multi-KiB streams into it.

Fields

§program: String

The program that exited non-zero.

§code: i32

The raw process exit code.

§stdout: String

Captured standard output, in full. Not shown in the Display message; kept for callers that need a stdout-borne failure message. For the raw-bytes helper (output_bytes) this is a lossy UTF-8 decode of stdout — the exact bytes remain on the originating ProcessResult.

§stderr: String

Captured standard error, in full. Only its last non-empty line (bounded) appears in the Display message — the complete captured text lives here, never poisoning a log line.

§

Timeout

The process exceeded its configured timeout and was killed.

Carries whatever the run captured before the deadline killed it (D12): a hung tool’s partial stderr is frequently the explanation (waiting for lock held by pid 4123, connecting to db…), so it is reachable via diagnostic and the public fields rather than lost. Empty when the producing path captured nothing (a streaming probe such as first_line, which never buffers).

The one-line Display message appends the last non-empty line of diagnostic, capped at 200 bytes — just like Exit — so a log line stays actionable without dumping the captured streams.

Fields

§program: String

The program that timed out.

§timeout: Duration

The deadline that elapsed.

§stdout: String

Standard output captured before the kill, in full. Not shown in the Display message (only its bounded diagnostic tail is). Empty when the path captured nothing. For the raw-bytes helper this is a lossy UTF-8 decode; the exact bytes remain on the originating ProcessResult.

§stderr: String

Standard error captured before the kill, in full — often the explanation of why the tool hung. Only its last non-empty line (bounded) reaches the Display message.

§

OutputTooLarge

The captured output exceeded the OverflowMode::Error fail-loud ceiling — a line cap (max_lines), a byte cap (max_bytes), or both. The run itself may have succeeded; this error is raised by the consuming path after the run completes.

The pipe is still fully drained (the child never blocks); output past the ceiling is counted (in the totals) but not retained.

Fields

§program: String

The program whose output exceeded the ceiling.

§line_limit: Option<usize>

The configured line ceiling, if any (OutputBufferPolicy::max_lines).

§byte_limit: Option<usize>

The configured byte ceiling, if any (OutputBufferPolicy::max_bytes).

§total_lines: usize

Total lines that arrived (retained + dropped).

§total_bytes: usize

Total bytes of decoded line text seen (retained + dropped) — the same unit max_bytes caps: the sum of line lengths with the trailing newline (and one \r) stripped, not the raw stream size.

§

NotReady

A readiness probe (RunningProcess::wait_for_line, wait_for_port, wait_for) did not pass within its deadline — the line never appeared, the port never accepted, the check never returned true, or the child exited before becoming ready.

Distinct from Timeout: a probe deadline is separate from the run’s own Command::timeout, and a failed probe does not kill the child — the caller decides what happens next.

Fields

§program: String

The program that did not become ready.

§timeout: Duration

The probe deadline that elapsed (or would have — an early child exit fails the probe immediately).

§

Parse

The process succeeded but its output could not be parsed into the expected shape (e.g. malformed --json). Produced by the fallible-parse helpers on CliClient.

message is caller-built and routinely embeds the unparsed output in full, so — like the Exit streams — both Display and Debug bound it to a 200-byte preview (B14); the complete text stays reachable via the public field.

Fields

§program: String

The program whose output failed to parse.

§message: String

What went wrong. Carried in full; only Display/Debug are bounded.

§

Unsupported

An operation is not supported by the active containment mechanism on this platform.

Raised by ProcessGroup::signal for any signal other than Signal::Kill on Windows (Job Objects have no POSIX signals).

Fields

§operation: String

A short description of the operation, e.g. "signal(Hup)" or "suspend".

§

Cancelled

The run was cancelled via its CancellationToken (Command::cancel_on) and its process tree was killed.

Asymmetric with Timeout by design: a timeout is captured (ProcessResult::timed_out) on the non-checking paths, whereas a cancellation is always raised on every consuming path. When a run both times out and is cancelled, cancellation wins (it is checked first).

Unlike Timeout / Signalled, this carries no captured streams (D12): cancellation is a deliberate caller action that stops the run immediately. On the pre-spawn path (the token was already cancelled) nothing was captured at all; on the consuming verbs, any output captured before the kill is intentionally discarded — the caller initiated the stop and knows why, so a partial diagnostic would be noise. diagnostic returns None.

Fields

§program: String

The program that was cancelled.

§

Signalled

The process was terminated by a signal (Unix) without producing an exit code. signal carries the signal number when the platform reports one (None on Windows or when the kernel does not expose it).

Distinct from Exit: a signal-terminated run has no exit code to check — it is always a failure. Produced by ensure_success and the require_code path when the outcome is Outcome::Signalled.

Carries whatever the run captured before the signal killed it (D12) — a crashing tool’s partial stderr is often the diagnostic — reachable via diagnostic and the public fields. The one-line Display appends the bounded diagnostic tail, like Exit.

Fields

§program: String

The program that was killed by a signal.

§signal: Option<i32>

The signal number, when reported by the platform.

§stdout: String

Standard output captured before the kill, in full. Not shown in the Display message (only its bounded diagnostic tail is). For the raw-bytes helper this is a lossy UTF-8 decode of stdout.

§stderr: String

Standard error captured before the kill, in full. Only its last non-empty line (bounded) reaches the Display message.

§

Stdin

The child ran but feeding its standard input failed for a reason other than the routine broken pipe.

Per [Decision 2], this is raised by the consuming paths only when the run otherwise succeeded — a non-zero Exit, a Signalled, or a Timeout is the “realer” failure and wins (the stdin error is then dropped). A broken pipe (EPIPE / ERROR_BROKEN_PIPE — the child closing stdin before reading all of it) is routine and never surfaces. Diagnoses a silently-truncated input the otherwise-successful child may have acted on.

[Decision 2]: the stdin source (Command::stdin) is written on a background task; this carries that task’s failure.

The io-level classifiers (is_transient, is_not_found, is_permission_denied) deliberately return false here: they classify spawn/launch conditions, and the run already succeeded — a blanket retry would re-run a command that worked. Inspect source directly if a stdin-specific retry is wanted.

Fields

§program: String

The program whose standard-input write failed.

§source: Error

The underlying IO error (never a broken pipe).

§

Io(Error)

A low-level IO error from the crate’s own machinery — driving a child (waiting for exit, issuing a kill), controlling a process group (signalling, reaping, sampling stats), or reading/writing a cassette file. It is not a spawn/launch condition (those are Spawn / NotFound).

There is deliberately no blanket From<std::io::Error> (D13): the crate never lets an arbitrary foreign io::Error fall into this variant via ?. Every Io is constructed explicitly at a known site, so the io-level classifiers (is_transient, is_permission_denied) only ever see an IO error the crate itself produced — never an unrelated one a caller’s ? happened to route through here.

Implementations§

Source§

impl Error

Source

pub fn diagnostic(&self) -> Option<&str>

The best human-facing message for a failed run, trimmed of surrounding whitespace: captured standard error if it carries text, otherwise the captured standard output (where git puts CONFLICT … and git commit puts nothing to commit). Covers the variants that capture streams — a non-zero Exit, a Timeout (the partial output of a hung-then-killed tool, D12), and a Signalled crash. Returns None when there is no captured output to show — a silent run (both streams blank) or a variant that carries none (Spawn, Cancelled, Parse, Io) — so a caller can fall back to the Display message. For the raw, untrimmed stream match on the variant’s fields directly.

Source

pub fn is_not_found(&self) -> bool

Whether the program could not be located — it is not installed, not on PATH, or the given path does not resolve to an executable. True for NotFound and only that variant (D11): the launch path funnels every program-not-found failure into NotFound, so this is the one check a caller needs to surface a “command not installed?” hint.

false for every other variant — notably it does not fire for a missing or invalid working directory (a Spawn carrying NotFound/NotADirectory): a bad cwd is not a missing program, so the hint would mislead. It is also false for a program that is installed but can’t be executed directly (e.g. a Windows .cmd/.bat that needs cmd.exe — surfaced as Spawn).

Source

pub fn is_permission_denied(&self) -> bool

Whether this is a spawn/IO permission denial (EACCES/EPERM): the binary isn’t executable, or the OS refused the launch. True for Spawn / Io carrying PermissionDenied; false otherwise.

Source

pub fn is_transient(&self) -> bool

Whether this is a transient spawn/IO condition a bare retry can clear — interrupted (EINTR), would-block (EAGAIN), a busy resource, a text-file-busy executable mid-write (ETXTBSY), or a Windows sharing/lock violation. Classifies the Spawn/Io IO error only.

Scope: IO/spawn-level, never exit codes. Whether a tool’s non-zero Exit is retryable is domain-specific (a git 128 is not generically transient) — that stays the caller’s call. Timeout is also excluded by design; compose it if wanted: e.is_transient() || matches!(e, Error::Timeout { .. }).

Pairs with Command::retry: cmd.retry(3, backoff, |e| e.is_transient()).

Trait Implementations§

Source§

impl Debug for Error

Manual Debug (L22): bounds the Exit streams and redacts the PATH value, so {e:?} / .unwrap() neither dumps a multi-MiB stream nor logs an environment value. Every other variant mirrors what the derive would print.

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Display for Error

Source§

fn fmt(&self, __formatter: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more
Source§

impl Error for Error

Source§

fn source(&self) -> Option<&(dyn Error + 'static)>

Returns the lower-level source of this error, if any. Read more
1.0.0 · Source§

fn description(&self) -> &str

👎Deprecated since 1.42.0:

use the Display impl or to_string()

1.0.0 · Source§

fn cause(&self) -> Option<&dyn Error>

👎Deprecated since 1.33.0:

replaced by Error::source, which can support downcasting

Source§

fn provide<'a>(&'a self, request: &mut Request<'a>)

🔬This is a nightly-only experimental API. (error_generic_member_access)
Provides type-based access to context intended for error reports. Read more

Auto Trait Implementations§

§

impl !RefUnwindSafe for Error

§

impl !UnwindSafe for Error

§

impl Freeze for Error

§

impl Send for Error

§

impl Sync for Error

§

impl Unpin for Error

§

impl UnsafeUnpin for Error

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Any for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Source§

fn type_name(&self) -> &'static str

Source§

impl<T> AnySync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Sync + Send>

Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToString for T
where T: Display + ?Sized,

Source§

fn to_string(&self) -> String

Converts the given value to a String. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more