gleam-lang/gleam · error
write new line after diagnostic
Error message
write new line after diagnostic
What it means
In `Error::pretty`, each rendered diagnostic is written to the output buffer followed by `writeln!(buffer).expect("write new line after diagnostic")`. `writeln!` returns `Err` if the underlying writer fails; since the buffer is an in-memory `codespan` `Buffer` this should be infallible, so the `expect` asserts the invariant that writing to the buffer never fails. A panic here means the writer implementation or buffer state is broken.
Solutions
- Avoid piping the compiler output into commands that close the pipe early, or ignore SIGPIPE (`trap '' PIPE`)/use `std::io::sink`-safe output paths
- Upgrade Gleam — CLI output writing has been progressively hardened against broken pipes
- If embedding, pass the standard `Buffer::no_color()`/`Buffer::ansi()` which write to memory and cannot fail
Example fix
// before
writeln!(buffer).expect("write new line after diagnostic");
// after
if writeln!(buffer).is_err() {
return; // downstream writer is gone; stop rendering diagnostics
} Defensive patterns
Strategy: try-catch
Validate before calling
// check output sink writability before running the compiler, e.g. avoid closed pipes: // gleam build | head <-- avoid; use full output redirect instead
Try / catch
match std::process::Command::new("gleam").arg("build").output() {
Ok(out) => print!("{}", String::from_utf8_lossy(&out.stdout)),
Err(e) => eprintln!("compiler output failed: {e}"), // includes broken-pipe cases
} Prevention
- Do not pipe compiler output into commands that exit early (head, less -F); capture to a file instead
- Handle SIGPIPE in wrapper scripts (trap '' PIPE) or write diagnostics to stderr
- Embed with standard Buffer types, which write to memory and cannot fail
When it happens
Trigger: `writeln!(buffer)` returns `Err` — realistically only when `pretty` is (or becomes) callable with a custom `Buffer`-like writer whose `write` implementation errors (disk full, closed pipe such as `gleam build | head`, or a mocked writer in tests that intentionally fails).
Common situations: Piping compiler output to a short-lived reader (e.g. `gleam check | head -1`) where the pipe is closed (broken pipe), or embedding the library with a custom buffer backed by a failing sink.
Related errors
- Error printing produced invalid utf8
- Term must exist
- Unknown labels first label
- at least one choice
- bit array compilation with no choice
AI-assisted analysis of gleam-lang/gleam@49f8762da5 (2026-09-14).
Data as JSON: /api/errors/ac2c4f378bf7f0a3.
Report an issue: GitHub.
Appendix: source
Thrown at compiler-core/src/error.rs:1007
_ if value / 10 == 1 => format!("{value}th"),
1 => format!("{value}st"),
2 => format!("{value}nd"),
3 => format!("{value}rd"),
_ => format!("{value}th"),
}
}
impl Error {
pub fn pretty_string(&self) -> String {
let mut nocolor = Buffer::no_color();
self.pretty(&mut nocolor);
String::from_utf8(nocolor.into_inner()).expect("Error printing produced invalid utf8")
}
pub fn pretty(&self, buffer: &mut Buffer) {
for diagnostic in self.to_diagnostics() {
diagnostic.write(buffer);
writeln!(buffer).expect("write new line after diagnostic");
}
}
pub fn skipped_files_diagnostics(&self) -> HashMap<Utf8PathBuf, Diagnostic> {
let Error::Type {
skipped_modules, ..
} = self
else {
return HashMap::new();
};
skipped_modules
.iter()
.map(|skipped_module| {
let text = match &skipped_module.reason {
SkipReason::DependencyHasError { .. } => {
"The current module cannot be analysed because this \
imported module has errors."View on GitHub (pinned to 49f8762da5)