Errors, Interruption, and Process Lifecycle
Errors are language values with provenance
ShellError variants carry spans, labels, help, and nested sources. Commands
return operational errors, while a Value::Error may travel inside a stream so
lazy failures appear at the point of consumption. Collecting a ListStream
unwraps the first error unless a debug path intentionally preserves it.
Signals are cooperative
Signals
wraps an optional Arc<AtomicBool>. ListStream checks before every item;
long-running algorithms check periodically; external job control can signal or
kill processes. This is cancellation without async-future destruction.
Child output and exit are one resource
ByteStreamSource::Child retains stdout/stderr and shared exit-status state.
Converting or draining it consumes pipes, waits for status, runs job-control
callbacks, and turns nonzero exit into ShellError unless explicitly ignored.
The shell cannot report success merely because stdout reached EOF.
Duplex pipes require concurrent draining
When both stdout and stderr are captured, Nushell consumes one on a helper thread to avoid the classic deadlock where a child blocks on a full pipe while the parent waits on the other. Plugin streams similarly run background writers and propagate connection loss to stream readers.