gleam-lang/gleam · error
invalid constants should not reach code generation
Error message
invalid constants should not reach code generation
What it means
A defensive unreachable!() guard in the JavaScript code generator for constant expressions. When compiling a constant BinOp, only operators valid for constant folding should ever appear; RemainderInt on constants is rejected earlier (constant folding does not support integer remainder), so reaching this arm means a constant expression was not properly evaluated or filtered before code generation. It indicates an internal compiler bug — invalid constant expressions should be caught during constant evaluation, not during code emission.
Solutions
- Fix the invalid constant syntax in the source module (run `gleam check` to locate it).
- In tooling that uses compiler internals, stop the pipeline when errors are reported before codegen.
- If no error was surfaced but this panic fires, file a Gleam compiler bug.
Example fix
// before (internal pipeline)
let ir = lower(module);
let js = javascript::compile(ir); // panics on Invalid constant
// after
if module.error_count() > 0 { return Err(...); }
let js = javascript::compile(ir); Defensive patterns
Strategy: validation
Validate before calling
// abort before codegen when any constant failed to parse
if constants.iter().any(|c| matches!(c, Constant::Invalid { .. })) {
return Err(Error::parse_failed());
} Type guard
fn constant_is_valid(c: &Constant) -> bool {
!matches!(c, Constant::Invalid { .. })
} Try / catch
match std::panic::catch_unwind(|| codegen_constant(&c)) {
Ok(doc) => doc,
Err(_) => report_internal_compiler_bug(),
} Prevention
- Fix reported parse/type errors before attempting codegen.
- In compiler-embedding tooling, check error counts after each phase.
- Keep the compiler updated so error-recovery bugs are patched.
When it happens
Trigger: A module whose constant expression failed to parse/typecheck (leaving an `Invalid` node) is fed into the JavaScript code generation pass — typically only possible when invoking compiler internals without aborting on earlier errors.
Common situations: Compiler-as-library usage that skips error checks; compiler regression in error recovery that failed to record the error and stop.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Invalid bit array segment type reached code generation
- invalid expressions should not reach code generation
- record updates should not reach code generation
- todo constants should not reach code generation
- case with no subjects
AI-assisted analysis of gleam-lang/gleam@49f8762da5 (2026-09-14).
Data as JSON: /api/errors/e424e7a14c9ea02a.
Report an issue: GitHub.
Appendix: source
Thrown at compiler-core/src/javascript/expression.rs:2865
| BinOp::RemainderInt => {
unreachable!("invalid constant operator made it to code generation")
}
BinOp::Concatenate => {
let left = self.constant_expression(arena, context, left);
let right = self.constant_expression(arena, context, right);
docvec![arena, left, SPACE_PLUS_SPACE_DOCUMENT, right]
}
},
Constant::RecordUpdate { .. } => {
panic!("record updates should not reach code generation")
}
Constant::Todo { .. } => {
panic!("todo constants should not reach code generation")
}
Constant::Invalid { .. } => {
panic!("invalid constants should not reach code generation")
}
}
}
fn constant_bit_array(
&mut self,
arena: &'doc DocumentArena<'a, 'doc>,
segments: &'a [TypedConstantBitArraySegment],
context: Context,
) -> Document<'a, 'doc> {
self.tracker.bit_array_literal_used = true;
let segments_array = array(
arena,
segments.iter().filter_map(|segment| {
let value = match context {
Context::Constant => self.constant_expression(arena, context, &segment.value),
Context::Guard => self.guard_constant_expression(arena, &segment.value),
};View on GitHub (pinned to 49f8762da5)