jdx/mise · error
piped
Error message
piped
What it means
run_with_limits spawns a child with stdin piped, then takes the StdinChildPipe with expect("piped"). Because the child was created with Stdio::piped() for stdin, this can only fail if the internal construction changed — the expect documents an invariant rather than an expected runtime failure.
Solutions
- Restore Stdio::piped() for stdin when spawning the child in run_with_limits
- Use match/expect with a descriptive message and handle None gracefully if piped stdin becomes conditional
Example fix
// before
let mut stdin = child.stdin.take().expect("piped");
// after
let Some(mut stdin) = child.stdin.take() else {
return Err(anyhow!("child stdin was not piped"));
}; Defensive patterns
Strategy: try-catch
Try / catch
// if contributing upstream, prefer explicit handling over expect
let Some(mut stdin) = child.stdin.take() else {
return Err(anyhow!("stdin not piped"));
}; Prevention
- Keep Stdio::piped() paired with the take() calls
- Add a test asserting the child's stdio configuration
- Never refactor stdio setup without running describe_command tests
When it happens
Trigger: Calling describe_command's run/run_with_limits when the child process creation code no longer configures stdin as piped — i.e. only after a code change breaks the invariant; not triggerable from user input.
Common situations: Developers modifying describe_command.rs and changing the Command's stdio configuration; reviewers seeing this panic in CI after such a change.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- affected project exists in graph
- an operation record always has an operation
- attestation requests must not have a streaming body
- bootstrap command is registered
- BootstrapPart values have clap names
AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17).
Data as JSON: /api/errors/6ca0e43045613973.
Report an issue: GitHub.
Appendix: source
Thrown at src/system/history/describe_command.rs:146
use std::os::unix::process::CommandExt;
// its own process group: a timeout ends what the shell started too
shell.process_group(0);
}
#[cfg(windows)]
let (mut child, job) = windows_job::spawn(&mut shell)?;
#[cfg(not(windows))]
let mut child = shell.spawn()?;
let active = ActiveCommand(RunningCommand {
pid: child.id(),
#[cfg(windows)]
job: std::sync::Arc::new(job),
});
if let Ok(mut running) = RUNNING.lock() {
*running = Some(active.0.clone());
}
// stdin is written and closed on its own thread: a command that answers
// before reading everything must not block us
let mut stdin = child.stdin.take().expect("piped");
std::thread::spawn(move || {
let _ = stdin.write_all(&input);
});
let stdout = child.stdout.take().expect("piped");
let (sender, receiver) = std::sync::mpsc::channel();
std::thread::spawn(move || {
let mut out = Vec::new();
let _ = stdout.take(DIFF_LIMIT as u64 + 1).read_to_end(&mut out);
let _ = sender.send(out);
});
let started = Instant::now();
let status = loop {
if let Some(status) = child.try_wait()? {
break status;
}
if started.elapsed() >= timeout {
// the shell and whatever it started; the reader thread ends
// with the last writer of the pipe, so it is not waited forView on GitHub (pinned to 533346cc37)