Skip to content

Commit 2d97d12

Browse files
committed
fix(cli): handle Windows EINVAL on broken-pipe flush
On Windows, flushing stdout after the reader closes the pipe raises OSError EINVAL, not BrokenPipeError. Catch that case too so piping help output to `head` exits cleanly instead of dumping a traceback. Assisted-by: ClaudeCode:claude-opus-4.8
1 parent 69b4bf1 commit 2d97d12

1 file changed

Lines changed: 7 additions & 2 deletions

File tree

plumbum/cli/application.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
}
1414

1515
import contextlib
16+
import errno
1617
import functools
1718
import inspect
1819
import os
@@ -1028,10 +1029,14 @@ def run(
10281029
if exit:
10291030
# surface an EPIPE now, while we can still handle it below
10301031
sys.stdout.flush()
1031-
except BrokenPipeError:
1032-
# The reader closed the pipe (e.g. output piped to ``head``).
1032+
except OSError as exc:
1033+
# The reader closed the pipe (e.g. output piped to ``head``). On
1034+
# POSIX this is BrokenPipeError (EPIPE); on Windows the flush
1035+
# raises OSError EINVAL instead. Re-raise anything else.
10331036
# Never change the SIGPIPE disposition instead: that would make a
10341037
# socket send() to a closed peer kill the whole process.
1038+
if not isinstance(exc, BrokenPipeError) and exc.errno != errno.EINVAL:
1039+
raise
10351040
retcode = 1
10361041
if exit:
10371042
# Point stdout at devnull so the interpreter's final flush

0 commit comments

Comments
 (0)