{"record":{"id":"a9fa8c55a2508fc7","repo":"gleam-lang/gleam","slug":"pattern-index","errorCode":null,"errorMessage":"pattern index","messagePattern":"pattern index","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler-core/src/exhaustiveness.rs","lineNumber":3660,"sourceCode":"    }\n\n    /// Registers a `TypedClause` as one of the branches to be compiled.\n    ///\n    /// If you don't have a clause and just have a simple `TypedPattern` you want\n    /// to generate a decision tree for you can use `add_pattern`.\n    ///\n    pub fn add_clause(&mut self, branch: &TypedClause) {\n        let all_patterns =\n            std::iter::once(&branch.pattern).chain(branch.alternative_patterns.iter());\n\n        for (alternative_index, patterns) in all_patterns.enumerate() {\n            let mut checks = Vec::with_capacity(patterns.len());\n\n            // We're doing the zipping ourselves instead of using iters.zip as the\n            // borrow checker would complain and the only workaround would be to\n            // allocate an entire new vector each time.\n            for i in 0..patterns.len() {\n                let pattern = self.register(patterns.get(i).expect(\"pattern index\"));\n                let var = self\n                    .subject_variables\n                    .get(i)\n                    .expect(\"wrong number of subjects\");\n                checks.push(var.is(pattern));\n            }\n\n            let has_guard = branch.guard.is_some();\n            let branch = Branch::new(self.number_of_clauses, alternative_index, checks, has_guard);\n            self.branches.push(branch);\n        }\n\n        self.number_of_clauses += 1;\n    }\n\n    /// Add a single pattern as a branch to be compiled.\n    ///\n    /// This is useful in case one wants to check exhaustiveness of a single","sourceCodeStart":3642,"sourceCodeEnd":3678,"githubUrl":"https://github.com/gleam-lang/gleam/blob/49f8762da595eb3c8f576656a4200a142ca188c9/compiler-core/src/exhaustiveness.rs#L3642-L3678","documentation":"Panic while registering all subject patterns of a multi-subject case expression: `patterns.get(i)` returned None for index i. The surrounding loop iterates `0..patterns.len()` against the same vec, so a failure means `patterns` was mutated during iteration or the loop bounds came from a different collection.","triggerScenarios":"Compiling a case expression with multiple subjects where `register` (called inside the loop) recursively triggers re-entry that drains/mutates `patterns`, or where the loop's `patterns.len()` and the vec being indexed are different collections that diverged.","commonSituations":"Gleam compiler contributors hit this when adding side effects inside `register` that mutate the pattern store, or after refactoring subject pattern collection so the vec is rebuilt mid-loop.","solutions":["Make sure `self.register` does not mutate or replace `self.patterns` during the loop (take a snapshot or use an iterator over the original vec).","Use `patterns.iter().zip(subject_variables.iter())` with collected results instead of index-based iteration to avoid shared-borrow workarounds.","Add a debug assert that `patterns.len()` matches `subject_variables.len()` before the loop (the adjacent 'wrong number of subjects' expect covers the other side)."],"exampleFix":"// before\nlet pattern = self.register(patterns.get(i).expect(\"pattern index\"));\n// after\nlet Some(p) = patterns.get(i) else {\n    panic!(\"pattern index {} out of {} patterns\", i, patterns.len())\n};\nlet pattern = self.register(p);","handlingStrategy":"validation","validationCode":"assert_eq!(patterns.len(), subject_variables.len(), \"subjects and variables out of sync\");\nfor (pattern, var) in patterns.iter().zip(subject_variables.iter()) { /* ... */ }","typeGuard":"fn paired_subjects<'a>(p: &'a [Id<Pattern>], v: &'a [Variable]) -> Option<std::vec::Vec<(&'a Id<Pattern>, &'a Variable)>> {\n    if p.len() == v.len() { Some(p.iter().zip(v.iter()).collect()) } else { None }\n}","tryCatchPattern":"std::panic::catch_unwind(|| register_subjects(patterns)).map_err(|_| Bug::PatternIndexOutOfRange)","preventionTips":["Avoid index loops over vecs that `register` may mutate; use iterators or snapshots.","Keep subject pattern and variable collections in lockstep length.","Never trigger re-entrant registration inside a loop over the same store."],"tags":["rust","compiler","panics","exhaustiveness","patterns"],"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"}