gleam-lang/gleam · error
unknown variant index
Error message
unknown variant index
What it means
Panic when matching a `RuntimeCheckKind::Variant { index }` against a `BranchMode::NamedType`: `constructors.get(index)` returned None. The variant index recorded in the check must be valid for the constructors of the named type at that node; if not, the check and the branch were built from different types.
Solutions
- Rebuild the Variant check from the current branch's constructors instead of carrying a stale positional index.
- Verify the subject type used to build the RuntimeCheckKind is the same NamedType stored in BranchMode::NamedType.
- Return an unreachable/bug error instead of panicking, and reduce the failing module to a minimal repro to file upstream.
Example fix
// before
constructors.get(index).expect("unknown variant index")
// after
constructors.get(index).unwrap_or_else(|| {
panic!("variant index {} invalid for {} constructors", index, constructors.len())
}) Defensive patterns
Strategy: validation
Validate before calling
assert!(index < constructors.len(), "variant index {} invalid for this branch", index); Type guard
fn constructor_for(constructors: &[Constructor], index: usize) -> Option<&Constructor> {
constructors.get(index)
} Try / catch
std::panic::catch_unwind(|| compile_check(check)).map_err(|_| Bug::UnknownVariantIndex(index))
Prevention
- Build RuntimeCheckKind::Variant from the same type stored in BranchMode::NamedType.
- Re-derive indices after type substitution instead of carrying them.
- Keep a mapping from variant name to per-type index rather than raw positions.
When it happens
Trigger: Compiling a variant check whose `index` exceeds the constructor count of the branch's NamedType — typically after a type substitution changed the subject's type, or a check was built for a different variant-bearing type and reused at the wrong node.
Common situations: Seen by Gleam compiler contributors after changes to type inference/unification feeding exhaustiveness, or when custom types are reordered between check construction and tree compilation.
Related errors
- wrong index for inferred variant
- 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/865273a57ff2c46e.
Report an issue: GitHub.
Appendix: source
Thrown at compiler-core/src/exhaustiveness.rs:2697
&mut self,
kind: RuntimeCheckKind,
branch_mode: &BranchMode,
) -> RuntimeCheck {
match (kind, branch_mode) {
(RuntimeCheckKind::Int { int_value }, _) => RuntimeCheck::Int { int_value },
(RuntimeCheckKind::Float { float_value }, _) => RuntimeCheck::Float { float_value },
(RuntimeCheckKind::String { value }, _) => RuntimeCheck::String { value },
(RuntimeCheckKind::StringPrefix { prefix }, _) => RuntimeCheck::StringPrefix {
prefix,
rest: self.fresh_variable(string()),
},
(RuntimeCheckKind::Tuple { .. }, BranchMode::Tuple { elements }) => {
self.is_tuple_check(elements)
}
(RuntimeCheckKind::Variant { index }, BranchMode::NamedType { constructors, .. }) => {
self.is_variant_check(
index,
constructors.get(index).expect("unknown variant index"),
)
}
(RuntimeCheckKind::EmptyList, _) => RuntimeCheck::EmptyList,
(RuntimeCheckKind::NonEmptyList, BranchMode::List { inner_type }) => {
self.is_list_check(inner_type.clone())
}
(_, _) => unreachable!("type checking should make this impossible"),
}
}
/// Comes up with new pattern cecks that have to match in case a given
/// runtime check succeeds for the given pattern.
///
/// Let's make an example: when we have a pattern - say `a is Wibble(1, [])` -
/// we come up with a runtime check to perform on it. For our example the
/// runtime check is to make sure that `a` is indeed a `Wibble` variant.
/// However, after successfully performing that check we're left with much to
/// do! We know that `a` is `Wibble` but now we'll have to make sure that itsView on GitHub (pinned to 49f8762da5)