{"record":{"id":"441bb694fe72ec8d","repo":"gleam-lang/gleam","slug":"writing-warning-to-stderr","errorCode":null,"errorMessage":"Writing warning to stderr","messagePattern":"Writing warning to stderr","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler-cli/src/fs.rs","lineNumber":892,"sourceCode":"            action: FileIoAction::Canonicalise,\n            kind: FileKind::File,\n            path: Utf8PathBuf::from(path),\n            err: Some(err.to_string()),\n        })\n        .map(|pb| Utf8PathBuf::from_path_buf(pb).expect(\"Non Utf8 Path\"))\n}\n\n#[derive(Debug, Clone, Copy)]\npub struct ConsoleWarningEmitter;\n\nimpl WarningEmitterIO for ConsoleWarningEmitter {\n    fn emit_warning(&self, warning: Warning) {\n        let buffer_writer = crate::cli::stderr_buffer_writer();\n        let mut buffer = buffer_writer.buffer();\n        warning.pretty(&mut buffer);\n        buffer_writer\n            .print(&buffer)\n            .expect(\"Writing warning to stderr\");\n    }\n}\n\n/// Returns root of Git repository in base path if it is initialised.\npub fn get_git_repository_root(mut path: Utf8PathBuf) -> Option<Utf8PathBuf> {\n    loop {\n        if path.join(\".git\").is_dir() {\n            return Some(path);\n        }\n\n        path = {\n            let path = path.parent()?;\n            path.into()\n        }\n    }\n}\n\n#[derive(Debug)]","sourceCodeStart":874,"sourceCodeEnd":910,"githubUrl":"https://github.com/gleam-lang/gleam/blob/7e623aa83da3776faee50ca4ab9a6c40124acd95/compiler-cli/src/fs.rs#L874-L910","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Redirect stderr to a file instead of a pipe that can close early: `gleam build 2>warnings.txt`.","If you must pipe, keep the reader alive for the whole run (use `| cat` or `| less -X` rather than `| head`).","Reduce warning volume first (fix warnings, or pass --warnings-as-errors in CI) so fewer writes happen.","If embedding the CLI, swap ConsoleWarningEmitter for a WarningEmitterIO implementation that maps io::Error to a graceful skip instead of expect."],"exampleFix":"# before: reader exits after 5 lines, later warning writes get EPIPE\ngleam build 2>&1 | head -n 5\n\n# after: stderr captured to a file, no broken pipe possible\ngleam build 2>warnings.txt; head -n 5 warnings.txt","handlingStrategy":"fallback","validationCode":"# CLI users: verify fd 2 is writable before a long build\nif ! (echo -n '' >&2) 2>/dev/null; then exec 2>gleam-stderr.log; fi\ngleam build","typeGuard":null,"tryCatchPattern":"// Embedders: implement a warning emitter that degrades gracefully\nstruct TolerantWarningEmitter;\nimpl WarningEmitterIO for TolerantWarningEmitter {\n    fn emit_warning(&self, warning: Warning) {\n        let w = cli::stderr_buffer_writer();\n        let mut buf = w.buffer();\n        warning.pretty(&mut buf);\n        if w.print(&buf).is_err() {\n            // stderr is gone (EPIPE); drop the warning instead of panicking\n            let _ = std::fs::write(\"gleam-warnings.log\", format!(\"{warning:?}\"));\n        }\n    }\n}","preventionTips":["Redirect stderr to a file (`gleam build 2>warn.log`) in scripts instead of piping into short-lived readers like head.","Never close the read end of a pipe attached to gleam's stderr before the process exits.","Fix warnings or run with --warnings-as-errors in CI so late warning writes can't kill the build."],"tags":["panic","stderr","pipe","epipe","io","compiler-warnings","termcolor"],"backgroundTag":"broken-pipe","analyzedSha":"7e623aa83da3776faee50ca4ab9a6c40124acd95","analyzedAt":"2026-08-17T00:07:02.091Z","schemaVersion":2},"datasetVersion":"2026-08-17T04:17:16.089Z"}