gleam-lang/gleam · error
wrong index for inferred variant
Error message
wrong index for inferred variant
What it means
A panic raised when the exhaustiveness compiler builds checks for a `BranchMode::NamedType` branch whose `inferred_variant` index points past the list of that type's constructors. The index stored as the inferred variant must always index into the constructors vec; if it does not, the type-inference and exhaustiveness passes disagree.
Solutions
- Verify `inferred_variant` is computed against the same type whose `constructors` vec is in this BranchMode; recompute the index after any type substitution.
- Clear the stale `inferred_variant` (use `None`) when the type is re-inferred so the all-constructors path is taken instead.
- Reorder/lookup constructors by name instead of a captured positional index if constructor order can change.
Example fix
// before
let constructor = constructors.get(*index).expect("wrong index for inferred variant");
// after
let constructor = constructors.get(*index).unwrap_or_else(|| {
panic!("inferred variant {} out of range for {} constructors", index, constructors.len())
}); Defensive patterns
Strategy: validation
Validate before calling
if let Some(index) = inferred_variant {
assert!(index < constructors.len(), "inferred variant {} out of range", index);
} Type guard
fn valid_inferred_variant(index: Option<usize>, constructors: &[Constructor]) -> Option<usize> {
index.filter(|i| *i < constructors.len())
} Try / catch
std::panic::catch_unwind(|| compile_branch(branch)).map_err(|_| Bug::WrongIndexForInferredVariant)
Prevention
- Recompute inferred_variant after any type substitution or unification.
- Never reuse a variant index with a different NamedType's constructor list.
- Prefer storing variant identity (module + name) over positional index.
When it happens
Trigger: Compiling a case subject whose inferred variant index was recorded by type inference, but the constructor list was rebuilt/reordered (e.g. after inference changed the variant, or the type was a different NamedType than the one the index was computed for).
Common situations: Gleam compiler contributors encounter this after changes to variant inference, custom-type ordering, or when `inferred_variant` is carried over between two different subject types (e.g. after unification substituted the type).
Related errors
- unknown variant index
- at least one choice
- bit array compilation with no choice
- check to already be a choice
- empty bit array test
AI-assisted analysis of gleam-lang/gleam@49f8762da5 (2026-09-14).
Data as JSON: /api/errors/1f45c1387075df1f.
Report an issue: GitHub.
Appendix: source
Thrown at compiler-core/src/exhaustiveness.rs:2533
// decision tree node is only ever going to have two different paths:
// one to follow if the list is empty, and one to follow if it's not.
BranchMode::List { inner_type } => {
vec![
RuntimeCheck::EmptyList,
self.is_list_check(inner_type.clone()),
]
}
// If we know that a specific variant is inferred we will require just
// that one and not all the other ones we know for sure are not going to
// be there.
BranchMode::NamedType {
constructors,
inferred_variant: Some(index),
} => {
let constructor = constructors
.get(*index)
.expect("wrong index for inferred variant");
vec![self.is_variant_check(*index, constructor)]
}
// Otherwise we know we'll need a check for each of its possible variants.
BranchMode::NamedType { constructors, .. } => constructors
.iter()
.enumerate()
.map(|(index, constructor)| self.is_variant_check(index, constructor))
.collect_vec(),
};
// We then split all the branches using these checks and compile the
// choices they've been split up into.
let mut splitter = BranchSplitter::from_checks(known_checks);
self.split_branches(&mut splitter, branches, pivot_var.clone(), &branch_mode);
if branch_mode.is_infinite() {
// If the branching is infinite, that means we always need to also have
// a fallback (imagine you're pattern matching on an `Int` and put noView on GitHub (pinned to 49f8762da5)