Skip to content

Commit 9c198e9

Browse files
authored
fix: handle EIO stream errors gracefully in bin.ts (#505)
Fixes [CLI-H2](https://sentry.sentry.io/issues/7347407245/) — an unhandled `EIO: i/o error, read` that crashed the CLI during `sentry auth login` on a self-hosted macOS instance. ## Root Cause The `handleStreamError` function in `bin.ts` only special-cased `EPIPE` (broken pipe) and re-threw all other errors. When `stdout`/`stderr` emits an `EIO` error event (non-recoverable I/O failure on the stream fd), the `throw` inside the synchronous event handler becomes an uncaught exception — matching the `auto.node.onuncaughtexception` mechanism seen in the issue. ## Fix Add `EIO` to the stream error handler allowlist alongside `EPIPE`. Both are non-recoverable stream errors where the fd is unusable, so the CLI should exit cleanly rather than crash with a fatal unhandled exception. `EIO` (errno -5) occurs from low-level I/O failures: terminal device driver errors, broken PTYs, disk I/O failures on redirected output, or virtualized storage glitches — common on self-hosted instances.
1 parent 830f455 commit 9c198e9

File tree

1 file changed

+12
-4
lines changed

1 file changed

+12
-4
lines changed

src/bin.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,22 @@
66
* the full CLI with telemetry, middleware, and error recovery.
77
*/
88

9-
// Exit cleanly when downstream pipe consumer closes (e.g., `sentry issue list | head`).
10-
// EPIPE (errno -32) is normal Unix behavior — not an error. Node.js/Bun ignore SIGPIPE
11-
// at the process level, so pipe write failures surface as async 'error' events on the
12-
// stream. Without this handler they become uncaught exceptions.
9+
// Handle non-recoverable stream I/O errors gracefully instead of crashing.
10+
// - EPIPE (errno -32): downstream pipe consumer closed (e.g., `sentry issue list | head`).
11+
// Normal Unix behavior — not an error. Exit 0 because the CLI succeeded; the consumer
12+
// just stopped reading.
13+
// - EIO (errno -5): low-level I/O failure on the stream fd (e.g., terminal device driver
14+
// error, broken PTY, disk I/O failure on redirected output). Non-recoverable — the
15+
// stream is unusable and output may be incomplete. Exit 1 so callers (scripts, CI) know
16+
// the output was lost. Seen in CLI-H2 on self-hosted macOS with virtualized storage.
17+
// Without this handler these errors become uncaught exceptions.
1318
function handleStreamError(err: NodeJS.ErrnoException): void {
1419
if (err.code === "EPIPE") {
1520
process.exit(0);
1621
}
22+
if (err.code === "EIO") {
23+
process.exit(1);
24+
}
1725
throw err;
1826
}
1927

0 commit comments

Comments
 (0)