gleam-lang/gleam · critical
BEAM compiler instance exited: {status}
Error message
BEAM compiler instance exited: {status} What it means
Gleam keeps one long-lived Erlang/BEAM helper process (an escript started by `BeamCompilerInstance::new`) to compile .erl modules quickly. Before every request `BeamCompilerInstance::compile` calls `try_wait()` (compiler-cli/src/beam_compiler.rs:40-46); if the child has already exited it panics `BEAM compiler instance exited: {status}`. This is a broken-invariant abort — the compiler assumes its helper survives the whole session — and it takes down the `gleam` process.
Source
Thrown at compiler-cli/src/beam_compiler.rs:45
// A guard held for cleaning up the temporary file used to start the BEAM instance.
_source: tempfile::NamedTempFile,
}
impl BeamCompilerInstance {
pub fn compile(
&mut self,
out: &Utf8Path,
lib: &Utf8Path,
modules: &HashSet<Utf8PathBuf>,
stdio: Stdio,
) -> Result<Vec<String>, Error> {
// Check that the BEAM instance is still alive before attempting to use it.
let exit_status = self
.process
.try_wait()
.expect("access BEAM instance exit state");
if let Some(status) = exit_status {
panic!("BEAM compiler instance exited: {status}");
}
// Prepare work to send to the BEAM instance.
let args = format!(
"{{\"{}\", \"{}\", [\"{}\"]}}",
escape_path(lib),
escape_path(out.join("ebin")),
modules
.iter()
.map(|module| escape_path(out.join(paths::ARTEFACT_DIRECTORY_NAME).join(module)))
.join("\", \"")
);
tracing::debug!(args=?args, "call_beam_compiler");
writeln!(self.stdin.as_ref().expect("stdin present"), "{args}.").map_err(|e| {
Error::ShellCommand {
program: "escript".into(),View on GitHub (pinned to 7e623aa83d)
Solutions
- Verify Erlang works outside Gleam: `command -v escript` and `erl -noshell -eval 'io:format("ok~n").' -s init stop`
- Check for resource kills: `dmesg | grep -i -E 'oom|killed process'` or container runtime events; raise memory/pids limits
- Re-run the command — a fresh `gleam` invocation spawns a new BEAM instance; for the LSP, restart the editor or language server
- If it reproduces with healthy Erlang and no OOM, capture the exit status from the panic text and report it at https://github.com/gleam-lang/gleam/issues
Defensive patterns
Strategy: validation
Validate before calling
# verify Erlang can host the BEAM helper before building
command -v escript >/dev/null 2>&1 || { echo 'escript not on PATH'; exit 1; }
erl -noshell -eval 'io:format("erlang ok~n").' -s init stop || { echo 'erl unusable'; exit 1; }
gleam build Prevention
- Pin a known-good Erlang/OTP in CI (Gleam requires escript on PATH)
- Leave memory headroom above Erlang's footprint so the OOM killer never targets escript
- Restart the Gleam LSP after upgrading or removing Erlang so it re-spawns a fresh BEAM instance
When it happens
Trigger: The BEAM child dies between or during compile requests: the kernel OOM killer or a container memory limit kills escript, Erlang was uninstalled or corrupted while the session ran, security software kills the helper process, or the machine is unstable. (The adjacent `expect("access BEAM instance exit state")` is a separate near-impossible waitpid failure.)
Common situations: CI containers with tight `--memory`/`--pids-limit`; Docker/gVisor sandboxes where escript crashes; antivirus reaping child processes on Windows; a partially upgraded Erlang install; a long-lived Gleam LSP session spanning an Erlang upgrade or outage.
Related errors
- could not lock beam_compiler
- Non Utf-8 Path
- `panic` expression evaluated.
- Unable to start Tokio async runtime
- Unable to start Tokio async runtime
AI-assisted analysis of gleam-lang/gleam@7e623aa83d (2026-08-17).
Data as JSON: /api/errors/5e2a95e8f67b0907.
Report an issue: GitHub.