{"record":{"id":"1f45c1387075df1f","repo":"gleam-lang/gleam","slug":"wrong-index-for-inferred-variant","errorCode":null,"errorMessage":"wrong index for inferred variant","messagePattern":"wrong index for inferred variant","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler-core/src/exhaustiveness.rs","lineNumber":2533,"sourceCode":"            // decision tree node is only ever going to have two different paths:\n            // one to follow if the list is empty, and one to follow if it's not.\n            BranchMode::List { inner_type } => {\n                vec![\n                    RuntimeCheck::EmptyList,\n                    self.is_list_check(inner_type.clone()),\n                ]\n            }\n\n            // If we know that a specific variant is inferred we will require just\n            // that one and not all the other ones we know for sure are not going to\n            // be there.\n            BranchMode::NamedType {\n                constructors,\n                inferred_variant: Some(index),\n            } => {\n                let constructor = constructors\n                    .get(*index)\n                    .expect(\"wrong index for inferred variant\");\n                vec![self.is_variant_check(*index, constructor)]\n            }\n\n            // Otherwise we know we'll need a check for each of its possible variants.\n            BranchMode::NamedType { constructors, .. } => constructors\n                .iter()\n                .enumerate()\n                .map(|(index, constructor)| self.is_variant_check(index, constructor))\n                .collect_vec(),\n        };\n\n        // We then split all the branches using these checks and compile the\n        // choices they've been split up into.\n        let mut splitter = BranchSplitter::from_checks(known_checks);\n        self.split_branches(&mut splitter, branches, pivot_var.clone(), &branch_mode);\n        if branch_mode.is_infinite() {\n            // If the branching is infinite, that means we always need to also have\n            // a fallback (imagine you're pattern matching on an `Int` and put no","sourceCodeStart":2515,"sourceCodeEnd":2551,"githubUrl":"https://github.com/gleam-lang/gleam/blob/49f8762da595eb3c8f576656a4200a142ca188c9/compiler-core/src/exhaustiveness.rs#L2515-L2551","documentation":"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.","triggerScenarios":"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).","commonSituations":"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).","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."],"exampleFix":"// before\nlet constructor = constructors.get(*index).expect(\"wrong index for inferred variant\");\n// after\nlet constructor = constructors.get(*index).unwrap_or_else(|| {\n    panic!(\"inferred variant {} out of range for {} constructors\", index, constructors.len())\n});","handlingStrategy":"validation","validationCode":"if let Some(index) = inferred_variant {\n    assert!(index < constructors.len(), \"inferred variant {} out of range\", index);\n}","typeGuard":"fn valid_inferred_variant(index: Option<usize>, constructors: &[Constructor]) -> Option<usize> {\n    index.filter(|i| *i < constructors.len())\n}","tryCatchPattern":"std::panic::catch_unwind(|| compile_branch(branch)).map_err(|_| Bug::WrongIndexForInferredVariant)","preventionTips":["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."],"tags":["rust","compiler","panics","exhaustiveness","variants"],"backgroundTag":"index-out-of-bounds","analyzedSha":"49f8762da595eb3c8f576656a4200a142ca188c9","analyzedAt":"2026-09-14T11:14:59.388Z","contentChangedAt":"2026-09-14T11:14:59.388Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}