Skip to content

fix: don't panic when stdout pipe is already closed on Windows - #1951

Open
Mathjk wants to merge 2 commits into
eza-community:mainfrom
Mathjk:fix/windows-broken-pipe-help
Open

Mathjk wants to merge 2 commits into
eza-community:mainfrom
Mathjk:fix/windows-broken-pipe-help

Conversation

@Mathjk

@Mathjk Mathjk commented Sep 29, 2026

Copy link
Copy Markdown

Problem

On Windows, there is no SIGPIPE. When the process consuming eza's
output exits before eza writes — e.g. eza --help | rg where rg
errors out immediately and closes the read end — writes to stdout fail
with ERROR_NO_DATA (232) / ERROR_BROKEN_PIPE (109).

get_matches() sends --help/--version output and argument errors
through clap's Error::exit(), which prints via print!() /
println!() — and those macros panic with
failed printing to stdout when the write fails. This is the panic
reported downstream in BurntSushi/ripgrep#3372:

thread 'main' panicked at library\std\src\io\stdio.rs:1123:9:
failed printing to stdout: The pipe is being closed. (os error 232)

Fix

Parse with try_get_matches() and render help/version/parse errors
ourselves:

  • writes to a closed pipe are ignored instead of panicking;
  • the stdout/stderr split (Error::use_stderr()) and the original
    exit code (Error::exit_code()) are preserved, so --help still
    exits 0 and argument errors still exit with clap's code.

No behaviour change on Unix (SIGPIPE semantics are untouched) or when
stdout is a normal file/terminal.

Testing

  • cargo check, cargo fmt --check clean.
  • Verified exit-code parity: --help → 0, invalid args → clap error
    code, both on Linux and Windows builds.
  • On Windows, eza --help | <early-exit consumer> no longer panics in
    the clap output path; the write failure is swallowed and the process
    exits with the expected code.

Note: reproducing the exact panic locally is timing-dependent (a short
single write can slip through before the reader closes), but the panic
site is eliminated structurally rather than worked around.

On Windows there is no SIGPIPE; when the consumer of `eza`'s output
exits before eza writes (e.g. `eza --help | rg` where rg errors out
immediately), writes to stdout fail with ERROR_NO_DATA (232) or
ERROR_BROKEN_PIPE (109).

`get_matches()` delegates help/version and argument-error output to
clap's `Error::exit()`, which prints via `print!()`/`println!()` and
panics with "failed printing to stdout" when the write fails. Use
`try_get_matches()` instead and render the message ourselves, ignoring
write failures while still honouring the proper exit code and
stderr/stdout split.

Fixes the panic reported downstream in BurntSushi/ripgrep#3372.
The v0.23.5 bump commit updated most snapshot files but missed
these two --version/-v ptests, leaving trycmd red on main.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant