gleam-lang/gleam · error

wrong number of subject variables for pattern

Error message

wrong number of subject variables for pattern

What it means

`add_pattern` compiles a single top-level pattern and expects at least one registered subject variable, taking `subject_variables.first()`. If none exist the `.expect` panics with this message. It means `add_pattern` was called for a case expression that had no subjects, violating the compiler's invariant that every pattern has a subject.

Solutions

  1. Ensure `Compiler::new(env, variable_id, patterns)` receives a non-empty subject/pattern list before `add_pattern` is called
  2. Guard the caller: only call `add_pattern` when there is at least one subject for the case expression
  3. For subject-less cases, compile with an empty branch list path (`compile` handles the branches.is_empty() case differently)
  4. If triggered by real Gleam code, report a compiler bug with the minimal case expression

Example fix

// before
let var = self.subject_variables.first().expect("wrong number of subject variables for pattern");
// after
let var = self.subject_variables.first().copied().unwrap_or_else(|| panic!("add_pattern called with no subject variables"));
Defensive patterns

Strategy: validation

Validate before calling

if subjects.is_empty() {
    return Err(Error::CaseWithNoSubjects);
}

Type guard

fn has_subjects(compiler: &Compiler) -> bool { !compiler.subject_variables.is_empty() }

Prevention

When it happens

Trigger: Calling `add_pattern` on the exhaustiveness `Compiler` before `Compiler::new` was given any subjects, or with an empty subject list (e.g. desugaring a synthetic case with zero subjects).

Common situations: Seen during compiler development when constructing the exhaustiveness compiler programmatically — e.g. in tests or in a lowering pass that builds a case expression from code and passes an empty subject vector.

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


AI-assisted analysis of gleam-lang/gleam@15b07c7830 (2026-09-14). Data as JSON: /api/errors/f8fb45b59d50b5bd. Report an issue: GitHub.

Appendix: source

Thrown at compiler-core/src/exhaustiveness.rs:3583

            let branch = Branch::new(self.number_of_clauses, alternative_index, checks, 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) {
        let pattern = self.register(pattern);
        let var = self
            .subject_variables
            .first()
            .expect("wrong number of subject variables for pattern");
        let branch = Branch::new(self.number_of_clauses, 0, vec![var.is(pattern)], None);
        self.number_of_clauses += 1;
        self.branches.push(branch);
    }

    pub fn compile(self, env: &Environment<'_>) -> CompileCaseResult {
        let mut compiler = Compiler::new(env, self.variable_id, self.patterns);

        let decision = if self.branches.is_empty() {
            let var = self
                .subject_variables
                .first()
                .expect("case with no subjects")
                .clone();

            compiler.split_and_compile_with_pivot_var(var, VecDeque::new())
        } else {
            compiler.compile(self.branches.into())

View on GitHub (pinned to 15b07c7830)