Piping any command into head panics or errors instead of exiting quietly #106

Open
opened 2026-08-15 12:54:17 +00:00 by a73x · 0 comments
a73x commented 2026-08-15 12:54:17 +00:00 (Migrated from git.a73x.sh)

[claude 2026-08-15] Closing the read end of a pipe — | head, | less and quit — makes the tool panic. Standard Unix behaviour is to die silently on SIGPIPE.

Three different behaviours for the same event, depending on how the command writes stdout:

$ git-collab patch show <id> | head -4
Head: 9cfb8ccf -> main

thread 'main' panicked at library/std/src/io/stdio.rs:1165:9:
failed printing to stdout: Broken pipe (os error 32)
$ echo ${pipestatus[1]}
101

$ git-collab patch diff <id> | head -4
thread 'main' panicked ... Broken pipe (os error 32)     # exit 101

$ git-collab refs | head -3
issue, archived  1e821152a2d7  refs/collab/archive/issues/0316...
error: Broken pipe (os error 32)                          # exit 1

$ git-collab issue list | head -2                         # exit 0, silent

Cause: the commands that go through output::emit swallow the write error (let _ = writeln!(...) in src/output.rs:64), so they are already quiet. The ones writing println! directly panic, and refs propagates the io::Error up to the error: reporter.

Note the panic needs output that outlives the reader — issue list | head -2 looks fine only because the whole listing fits the 64KB pipe buffer before head exits. It is the same latent bug.

Expected: exiting 0 (or dying by SIGPIPE) with no output, for every command, however it writes.

Suggested fix: one exit path that treats ErrorKind::BrokenPipe as success, and route the direct println! sites through output::emit so there is one writer rather than three.


Migrated from git-collab issue 8baa9fa8a7ab0ec2b2fbff29fb342c4494221340.

Original author: a73x dev@a73x.sh.

[claude 2026-08-15] Closing the read end of a pipe — `| head`, `| less` and quit — makes the tool panic. Standard Unix behaviour is to die silently on SIGPIPE. Three different behaviours for the same event, depending on how the command writes stdout: ``` $ git-collab patch show <id> | head -4 Head: 9cfb8ccf -> main thread 'main' panicked at library/std/src/io/stdio.rs:1165:9: failed printing to stdout: Broken pipe (os error 32) $ echo ${pipestatus[1]} 101 $ git-collab patch diff <id> | head -4 thread 'main' panicked ... Broken pipe (os error 32) # exit 101 $ git-collab refs | head -3 issue, archived 1e821152a2d7 refs/collab/archive/issues/0316... error: Broken pipe (os error 32) # exit 1 $ git-collab issue list | head -2 # exit 0, silent ``` Cause: the commands that go through `output::emit` swallow the write error (`let _ = writeln!(...)` in src/output.rs:64), so they are already quiet. The ones writing `println!` directly panic, and `refs` propagates the io::Error up to the `error:` reporter. Note the panic needs output that outlives the reader — `issue list | head -2` looks fine only because the whole listing fits the 64KB pipe buffer before `head` exits. It is the same latent bug. Expected: exiting 0 (or dying by SIGPIPE) with no output, for every command, however it writes. Suggested fix: one exit path that treats `ErrorKind::BrokenPipe` as success, and route the direct `println!` sites through `output::emit` so there is one writer rather than three. --- Migrated from git-collab issue `8baa9fa8a7ab0ec2b2fbff29fb342c4494221340`. Original author: a73x <dev@a73x.sh>.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
a73x/git-collab#106
No description provided.