gleam-lang/gleam · error
Expression not fully reduced.
Error message
Expression not fully reduced.
What it means
At the end of the expression precedence-climbing loop, the parser expects exactly one fully reduced expression on the stack. If more than one expression remains after popping the final one, the reduction invariants were violated, so it panics. The `_ => return None` arm handles genuine parse failure (returns `None` so a proper parse error is reported).
Solutions
- Reduce the input to a minimal snippet that triggers the panic and file a Gleam compiler bug with it.
- If you are modifying the parser, audit operator handlers so every `push_operand` is balanced by `do_reduce_expression` calls.
- As a workaround, reformulate the expression (add explicit parentheses) — though a panic here usually indicates a compiler bug, not user error.
Defensive patterns
Strategy: try-catch
Try / catch
let parsed = std::panic::catch_unwind(|| parse_expression(tokens));
match parsed {
Ok(Some(expr)) => expr,
_ => report_compiler_bug("Expression not fully reduced"),
} Prevention
- Treat this panic as a compiler bug: reduce input to a minimal snippet and report it.
- Keep the Gleam compiler up to date; parser stack bugs get fixed in patches.
- When modifying parse.rs, keep every operand push balanced with operator reductions.
When it happens
Trigger: The infix expression parser's operator/operand stack bookkeeping goes out of sync — e.g. an operator handler pushes an expression without consuming one, or a bug in a new operator's precedence handling leaves two unreduced expressions stacked when the input ends.
Common situations: Gleam parser development/regressions; extremely rare for end users, since malformed input normally returns None and produces a normal parse error instead.
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 constants can not be in an untyped ast
- Token could not be converted to binop.
- Tried to reduce bit array size without 2 operands
- Tried to reduce without 2 expressions
- Tried to reduce without 2 guards
AI-assisted analysis of gleam-lang/gleam@15b07c7830 (2026-09-14).
Data as JSON: /api/errors/d6ef1091a5234c97.
Report an issue: GitHub.
Appendix: source
Thrown at compiler-core/src/parse.rs:4926
// Higher number means higher precedence.
// All operators are left associative.
/// Simple-Precedence-Parser, handle seeing an operator or end
fn handle_operator<A>(
next_operator: Option<(Spanned, u8)>,
operator_stack: &mut Vec<(Spanned, u8)>,
expression_stack: &mut Vec<A>,
do_reduce: &impl Fn(Spanned, &mut Vec<A>),
) -> Option<A> {
let mut next_operator = next_operator;
loop {
match (operator_stack.pop(), next_operator.take()) {
(None, None) => match expression_stack.pop() {
Some(fin) => {
if expression_stack.is_empty() {
return Some(fin);
} else {
panic!("Expression not fully reduced.")
}
}
_ => {
return None;
}
},
(None, Some(operator)) => {
operator_stack.push(operator);
break;
}
(Some((operator, _)), None) => do_reduce(operator, expression_stack),
(Some((left_operator, left_precedence)), Some((right_operator, right_precedence))) => {
match left_precedence.cmp(&right_precedence) {
// all operators are left associative
Ordering::Greater | Ordering::Equal => {View on GitHub (pinned to 15b07c7830)