Summary
numfmt calls .unwrap() on every write to stdout. When a write to the output fails for any reason other than a broken pipe (e.g. the output device is full, or the output file/redirect is no longer writable), the unwrap() turns the io::Error into a panic. Because the release profile builds with panic = "abort", the process aborts (SIGABRT, exit 134, core dumped) instead of printing a clean diagnostic and exiting with a normal error status.
GNU numfmt handles the same situation gracefully: it prints numfmt: write error: ... and exits with status 1.
Steps to reproduce
The simplest trigger is writing to /dev/full (every write fails with ENOSPC):
$ numfmt 1024 > /dev/full
thread 'main' panicked at src/uu/numfmt/src/format.rs:872:34:
called `Result::unwrap()` on an `Err` value: Os { code: 28, kind: StorageFull, message: "No space left on device" }
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Aborted (core dumped)
$ echo $?
134
Any output write failure reaches the same problem through one of several code paths (plain numbers, -d/delimited input, --padding, unselected fields, etc.).
Expected behavior
Match GNU: report the write error and exit non-zero, without panicking.
$ /usr/bin/numfmt 1024 > /dev/full
/usr/bin/numfmt: write error: No space left on device
$ echo $?
1
Actual behavior
The process panics and aborts (exit 134), emitting a Rust panic message and a core dump instead of a user-facing error.
Note: the common numfmt ... | head broken-pipe case is not affected — there the process is terminated by SIGPIPE as expected. This report is specifically about non-pipe write failures (full disk, closed/failed redirect target, etc.).
Root cause
The output helpers in src/uu/numfmt/src/format.rs unwrap their writes rather than propagating the error. There are ~10 writer.write_all(...).unwrap() calls across write_formatted_with_delimiter and write_formatted_with_whitespace, e.g.:
writer.write_all(formatted.as_bytes()).unwrap();
...
writer.write_all(&[eol]).unwrap();
Environment
- uutils coreutils:
numfmt (uutils coreutils) 0.8.0 (commit aaf4a35, 2026-05-27)
- rustc: 1.89.0
- Reference: GNU coreutils 8.30
Summary
numfmtcalls.unwrap()on every write to stdout. When a write to the output fails for any reason other than a broken pipe (e.g. the output device is full, or the output file/redirect is no longer writable), theunwrap()turns theio::Errorinto a panic. Because the release profile builds withpanic = "abort", the process aborts (SIGABRT, exit 134, core dumped) instead of printing a clean diagnostic and exiting with a normal error status.GNU
numfmthandles the same situation gracefully: it printsnumfmt: write error: ...and exits with status 1.Steps to reproduce
The simplest trigger is writing to
/dev/full(every write fails withENOSPC):Any output write failure reaches the same problem through one of several code paths (plain numbers,
-d/delimited input,--padding, unselected fields, etc.).Expected behavior
Match GNU: report the write error and exit non-zero, without panicking.
Actual behavior
The process panics and aborts (exit 134), emitting a Rust panic message and a core dump instead of a user-facing error.
Note: the common
numfmt ... | headbroken-pipe case is not affected — there the process is terminated bySIGPIPEas expected. This report is specifically about non-pipe write failures (full disk, closed/failed redirect target, etc.).Root cause
The output helpers in
src/uu/numfmt/src/format.rsunwrap their writes rather than propagating the error. There are ~10writer.write_all(...).unwrap()calls acrosswrite_formatted_with_delimiterandwrite_formatted_with_whitespace, e.g.:Environment
numfmt (uutils coreutils) 0.8.0(commitaaf4a35, 2026-05-27)