imsnif/bandwhich · error
Failed to write to stdout
Error message
Failed to write to stdout: {e} What it means
bandwhich writes its report snapshots to stdout from a dedicated thread. If a write to stdout fails and it is not a benign BrokenPipe (consumer exited), the code panics with this message rather than continuing with a broken output stream.
Solutions
- Ensure the consumer of bandwhich stdout (e.g. `bandwhich --raw | consumer`) stays alive and reads stdout continuously
- Check disk space / filesystem health if stdout is redirected to a file
- Run bandwhich in a terminal or with a valid pipe, not with a closed stdout (`bandwhich >&-`)
- If piping programmatically, handle BrokenPipe as normal shutdown and treat other io::Error kinds as fatal
Example fix
// before bandwhich | grep -m1 eth0 // after bandwhich --raw | while read line; do grep -m1 eth0 <<< "$line" && break; done; # keep reader alive until match
Defensive patterns
Strategy: try-catch
Validate before calling
// Rust (caller): only pipe when a live reader exists
use std::io::IsTerminal;
let safe = std::io::stdout().is_terminal() || reader_is_alive();
if !safe { eprintln!("stdout has no live reader; use --raw with a consuming pipe"); } Type guard
fn stdout_is_writable() -> bool {
use std::io::Write;
let mut out = std::io::stdout();
out.write_all(b"").is_ok()
} Try / catch
match stdout.write_all(&bytes) {
Ok(_) => {}
Err(e) if e.kind() == std::io::ErrorKind::BrokenPipe => std::process::exit(0),
Err(e) => eprintln!("stdout write failed: {e}"), // log & exit cleanly instead of panicking
} Prevention
- Always pipe bandwhich --raw into a process that consumes stdout until bandwhich exits
- Avoid redirecting stdout to files on full/disks or closed descriptors (`>&-`)
- Treat BrokenPipe as graceful shutdown, as bandwhich does
- Monitor disk space when redirecting output
When it happens
Trigger: Calling `create_write_to_stdout`'s spawned write task when stdout is closed, redirected to a failing file/pipe with a non-broken-pipe error (e.g. ENOSPC, EPIPE variant with different kind, EIO on a detached terminal), or the receiver ends of `stdout_write` are dropped.
Common situations: Piping bandwhich into a process that dies mid-run without a clean SIGPIPE, running with stdout redirected to a full disk, running under a supervisor that closes stdout, or running in environments (CI, systemd) where stdout is detached.
Understand the failure class
Background: "failed to write file", "Could not save figure", "Error saving remote file" — file write failed: causes and fixes across languages and libraries — this error's family across 38 libraries.
Related errors
- Failed to get stdout: if you are trying to pipe 'bandwhich'…
- Failed to find any network interface to listen on.
- {err_msg}
- failed to set SIGINT handler
- failed to execute process
AI-assisted analysis of imsnif/bandwhich@1899870cea (2026-09-08).
Data as JSON: /api/errors/102f298c17dc0d72.
Report an issue: GitHub.
Appendix: source
Thrown at src/os/shared.rs:103
}
fn get_interface(interface_name: &str) -> Option<NetworkInterface> {
datalink::interfaces()
.into_iter()
.find(|iface| iface.name == interface_name)
}
fn create_write_to_stdout() -> Box<dyn FnMut(&str) + Send> {
let mut stdout = io::stdout();
Box::new({
move |output| match writeln!(stdout, "{output}") {
Ok(_) => (),
Err(e) if e.kind() == ErrorKind::BrokenPipe => {
// A process that was listening to bandwhich stdout has exited
// We can't do much here, lets just exit as well
std::process::exit(0)
}
Err(e) => panic!("Failed to write to stdout: {e}"),
}
})
}
pub fn get_input(
interface_name: Option<&str>,
resolve: bool,
dns_server: Option<Ipv4Addr>,
) -> eyre::Result<OsInputOutput> {
// get the user's requested interface, if any
// IDEA: allow requesting multiple interfaces
let requested_interfaces = interface_name
.map(|name| get_interface(name).ok_or_else(|| eyre!("Cannot find interface {name}")))
.transpose()?
.map(|interface| vec![interface]);
// take the user's requested interfaces (or all interfaces), and filter for up ones
let available_interfaces = requested_interfacesView on GitHub (pinned to 1899870cea)