cli_stream/error.rs
1//! Typed errors for the streaming engine.
2
3/// Why [`spawn_streaming`](crate::spawn_streaming) or
4/// [`ProcessHandle::cancel`](crate::ProcessHandle::cancel) failed.
5///
6/// Carries the real underlying [`std::io::Error`] as a source (via
7/// [`std::error::Error::source`]) rather than a pre-formatted string, so a
8/// caller can downcast or inspect the OS error (e.g. distinguish
9/// `NotFound` — the binary isn't on `PATH` — from `PermissionDenied`).
10/// `#[non_exhaustive]` so adding a variant later isn't a breaking change.
11#[derive(Debug, thiserror::Error)]
12#[non_exhaustive]
13pub enum StreamError {
14 /// The child process could not be spawned: the binary isn't on `PATH`,
15 /// isn't executable, or the OS refused. `source` is the spawn `io::Error`
16 /// (commonly `NotFound`).
17 #[error("failed to spawn {program}: {source}")]
18 Spawn {
19 /// The program that failed to launch (as passed to the engine).
20 program: String,
21 /// The OS error from `Command::spawn`.
22 #[source]
23 source: std::io::Error,
24 },
25
26 /// The spawned child didn't expose a piped stdout/stderr. Shouldn't
27 /// happen given the engine requests `Stdio::piped()`, but `Child`'s pipe
28 /// accessors return `Option`, so the case is represented rather than
29 /// `unwrap`ped.
30 #[error("child {stream} pipe was not captured")]
31 PipeNotCaptured {
32 /// Which stream was missing — `"stdout"` or `"stderr"`.
33 stream: &'static str,
34 },
35
36 /// Cancellation couldn't acquire the child lock because it was poisoned
37 /// (a thread panicked while holding it). The process may still be
38 /// running; the caller can retry or give up.
39 #[error("cancel failed: the child lock was poisoned")]
40 CancelLockPoisoned,
41}