gleam-lang/gleam · error

Writing warning to stderr

Error message

Writing warning to stderr

What it means

ConsoleWarningEmitter::emit_warning pretty-prints every compiler warning to stderr through a termcolor BufferWriter and calls expect("Writing warning to stderr") on the print result. print returns io::Result, and it fails when the underlying write(2) to fd 2 fails — almost always EPIPE or EIO because the process reading gleam's stderr has gone away. The panic happens while printing a warning, so it can abort a build that otherwise succeeded.

Source

Thrown at compiler-cli/src/fs.rs:892

            action: FileIoAction::Canonicalise,
            kind: FileKind::File,
            path: Utf8PathBuf::from(path),
            err: Some(err.to_string()),
        })
        .map(|pb| Utf8PathBuf::from_path_buf(pb).expect("Non Utf8 Path"))
}

#[derive(Debug, Clone, Copy)]
pub struct ConsoleWarningEmitter;

impl WarningEmitterIO for ConsoleWarningEmitter {
    fn emit_warning(&self, warning: Warning) {
        let buffer_writer = crate::cli::stderr_buffer_writer();
        let mut buffer = buffer_writer.buffer();
        warning.pretty(&mut buffer);
        buffer_writer
            .print(&buffer)
            .expect("Writing warning to stderr");
    }
}

/// Returns root of Git repository in base path if it is initialised.
pub fn get_git_repository_root(mut path: Utf8PathBuf) -> Option<Utf8PathBuf> {
    loop {
        if path.join(".git").is_dir() {
            return Some(path);
        }

        path = {
            let path = path.parent()?;
            path.into()
        }
    }
}

#[derive(Debug)]

View on GitHub (pinned to 7e623aa83d)

Solutions

  1. Redirect stderr to a file instead of a pipe that can close early: `gleam build 2>warnings.txt`.
  2. If you must pipe, keep the reader alive for the whole run (use `| cat` or `| less -X` rather than `| head`).
  3. Reduce warning volume first (fix warnings, or pass --warnings-as-errors in CI) so fewer writes happen.
  4. If embedding the CLI, swap ConsoleWarningEmitter for a WarningEmitterIO implementation that maps io::Error to a graceful skip instead of expect.

Example fix

# before: reader exits after 5 lines, later warning writes get EPIPE
gleam build 2>&1 | head -n 5

# after: stderr captured to a file, no broken pipe possible
gleam build 2>warnings.txt; head -n 5 warnings.txt
Defensive patterns

Strategy: fallback

Validate before calling

# CLI users: verify fd 2 is writable before a long build
if ! (echo -n '' >&2) 2>/dev/null; then exec 2>gleam-stderr.log; fi
gleam build

Try / catch

// Embedders: implement a warning emitter that degrades gracefully
struct TolerantWarningEmitter;
impl WarningEmitterIO for TolerantWarningEmitter {
    fn emit_warning(&self, warning: Warning) {
        let w = cli::stderr_buffer_writer();
        let mut buf = w.buffer();
        warning.pretty(&mut buf);
        if w.print(&buf).is_err() {
            // stderr is gone (EPIPE); drop the warning instead of panicking
            let _ = std::fs::write("gleam-warnings.log", format!("{warning:?}"));
        }
    }
}

Prevention

When it happens

Trigger: Running any gleam command with stderr piped to a consumer that exits early: `gleam build 2>&1 | head -n 5`, `gleam check 2> >(head -1)` with process substitution, or CI wrappers that close the pipe. Also when fd 2 is closed (2>&-) or an SSH/terminal session dies mid-build while many warnings are being emitted.

Common situations: Piping compiler output into head/less/grep -m1 in scripts, editor task runners that kill the pipe after first output, detached processes whose stderr was a socket that closed, and sandboxed CI that revokes fd 2.

Related errors


AI-assisted analysis of gleam-lang/gleam@7e623aa83d (2026-08-17). Data as JSON: /api/errors/441bb694fe72ec8d. Report an issue: GitHub.