gleam-lang/gleam · error
wrong number of subjects
Error message
wrong number of subjects
What it means
This panic comes from an `.expect("wrong number of subjects")` inside the exhaustiveness (pattern-matching) compiler of the Gleam compiler core. When compiling a `case` expression's branches, each pattern list is zipped against the pre-registered subject variables; the length mismatch means a branch had more patterns than there were case subjects, which the typechecker should have rejected earlier. It is an internal invariant assertion, not a user-facing error.
Solutions
- Check the number of patterns in each clause matches the number of case subjects before registration; the parser/typechecker should report 'case clause has too many patterns' instead
- Verify the code that builds `subject_variables` pushes one variable per subject (look at where `Compiler::new` is called)
- Run with a debug build to get the full panic backtrace and identify which pass produced the oversized pattern vector
- If you are a library user (not compiler dev), this is a compiler bug — file an issue with the code that triggers it
Example fix
// before
let var = self.subject_variables.get(i).expect("wrong number of subjects");
// after
let var = self.subject_variables.get(i).unwrap_or_else(|| {
panic!("clause has {} patterns but {} subjects were registered", patterns.len(), self.subject_variables.len())
}); Defensive patterns
Strategy: validation
Validate before calling
if patterns.len() != subjects.len() {
return Err(Error::CaseClauseArityMismatch { patterns: patterns.len(), subjects: subjects.len() });
} Type guard
fn clause_matches_subjects(patterns: &[TypedPattern], subjects: &[Variable]) -> bool {
patterns.len() == subjects.len()
} Prevention
- Validate pattern arity per clause during typechecking before exhaustiveness compilation
- Add a debug_assert_eq!(patterns.len(), self.subject_variables.len()) before the loop
- Fuzz the frontend with multi-subject case expressions
- Keep a unit test per AST pass that constructs case expressions
When it happens
Trigger: Calling `Compiler::compile_body` (or the clause-registration path) with a `patterns` iterator/Vec longer than `subject_variables` — e.g. an earlier AST pass failed to keep pattern count equal to the number of case subjects for a multi-subject case clause.
Common situations: Hitting this while hacking on the Gleam compiler: adding a new pattern desugaring that duplicates patterns, miscounting subjects in a rewrite pass, or fuzzing the frontend with malformed case expressions that bypass the typechecker's arity check.
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
- case with no subjects
- Custom type constructor exist for type
- Custom type constructor must have custom type kind
- Should be a named type
- wrong number of subject variables for pattern
AI-assisted analysis of gleam-lang/gleam@49f8762da5 (2026-09-14).
Data as JSON: /api/errors/c11e019cd6a562e8.
Report an issue: GitHub.
Appendix: source
Thrown at compiler-core/src/exhaustiveness.rs:3664
/// If you don't have a clause and just have a simple `TypedPattern` you want
/// to generate a decision tree for you can use `add_pattern`.
///
pub fn add_clause(&mut self, branch: &TypedClause) {
let all_patterns =
std::iter::once(&branch.pattern).chain(branch.alternative_patterns.iter());
for (alternative_index, patterns) in all_patterns.enumerate() {
let mut checks = Vec::with_capacity(patterns.len());
// We're doing the zipping ourselves instead of using iters.zip as the
// borrow checker would complain and the only workaround would be to
// allocate an entire new vector each time.
for i in 0..patterns.len() {
let pattern = self.register(patterns.get(i).expect("pattern index"));
let var = self
.subject_variables
.get(i)
.expect("wrong number of subjects");
checks.push(var.is(pattern));
}
let has_guard = branch.guard.is_some();
let branch = Branch::new(self.number_of_clauses, alternative_index, checks, has_guard);
self.branches.push(branch);
}
self.number_of_clauses += 1;
}
/// Add a single pattern as a branch to be compiled.
///
/// This is useful in case one wants to check exhaustiveness of a single
/// pattern without having a fully fledged `TypedClause` to pass to the `add_clause`
/// method. For example, in `let` destructurings.
///
pub fn add_pattern(&mut self, pattern: &TypedPattern) {View on GitHub (pinned to 49f8762da5)