jdx/mise · error

command output pipes did not close within

Error message

command output pipes did not close within {pipe_drain_timeout:?}

What it means

After the command process exits, execute_hashes_async_with_drain_timeout waits up to pipe_drain_timeout for the stdout/stderr pipes to close (all buffered output consumed). If the deadline expires or a remaining-drain recv times out, the process tree is SIGKILLed and this error is thrown. It means grandchildren/descendants still hold the pipes open, so output may be incomplete.

Solutions

  1. Redirect background children's output to files or /dev/null (e.g. `child --daemon > /dev/null 2>&1 &`) so the pipes close when the parent exits
  2. Increase the pipe_drain_timeout at the call site if legitimate slow output needs more time
  3. Fix the task so it waits for or detaches its children properly instead of leaving them holding the pipes

Example fix

// before
my-task &  # background child keeps stdout/stderr pipe open -> drain timeout
// after
nohup my-task > /tmp/my-task.log 2>&1 < /dev/null &
Defensive patterns

Strategy: try-catch

Validate before calling

// prefer tasks whose children detach their own output
// grep your script for background spawns inheriting stdout:
//   grep -nE '(^|[^>]*)&( |$)' script.sh

Try / catch

match cmd.execute_hashes_async(MAX).await {
    Ok(h) => Ok(h),
    Err(e) if e.to_string().contains("pipes did not close") => {
        // kill orphans, then retry with children redirected
        cleanup_orphans();
        cmd.execute_hashes_async(MAX).await
    }
    Err(e) => Err(e),
}

Prevention

When it happens

Trigger: The main command exits but spawned background children or grandchildren inherit stdout/stderr and keep the pipes open beyond pipe_drain_timeout; the recv timeout in the drain loop elapses with remaining time at zero.

Common situations: Tasks that daemonize or launch background servers (watchers, dev servers) that inherit the parent's output pipes; scripts spawning long-lived children without redirecting their output.

Understand the failure class

Background: Request timed out: what client-side request timeouts mean across libraries (Request timed out, TIMED_OUT, APITimeoutError) — this error's family across 39 libraries.

Related errors


AI-assisted analysis of jdx/mise@533346cc37 (2026-09-17). Data as JSON: /api/errors/c6dba2ce5504e0e8. Report an issue: GitHub.

Appendix: source

Thrown at src/cmd.rs:1442

                        #[cfg(unix)]
                        signal_process_tree(id, nix::sys::signal::Signal::SIGKILL);
                        #[cfg(windows)]
                        kill_process_tree(id);
                        let _ = wait.await;
                        return Err(err);
                    }
                }
            }
        }
        let drain_deadline = Instant::now() + pipe_drain_timeout;
        loop {
            let remaining = drain_deadline.saturating_duration_since(Instant::now());
            if remaining.is_zero() {
                #[cfg(unix)]
                signal_process_tree(id, nix::sys::signal::Signal::SIGKILL);
                #[cfg(windows)]
                kill_process_tree(id);
                bail!("command output pipes did not close within {pipe_drain_timeout:?}");
            }
            let output = match tokio::time::timeout(remaining, rx.recv()).await {
                Ok(Some(output)) => output,
                Ok(None) => break,
                Err(_) => {
                    #[cfg(unix)]
                    signal_process_tree(id, nix::sys::signal::Signal::SIGKILL);
                    #[cfg(windows)]
                    kill_process_tree(id);
                    bail!("command output pipes did not close within {pipe_drain_timeout:?}");
                }
            };
            if let Err(err) = consume(output) {
                #[cfg(unix)]
                signal_process_tree(id, nix::sys::signal::Signal::SIGKILL);
                #[cfg(windows)]
                kill_process_tree(id);
                return Err(err);

View on GitHub (pinned to 533346cc37)