a73x

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

open   by a73x

Labels: backlog

[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.