{"record":{"id":"93936bc32d1bda82","repo":"gleam-lang/gleam","slug":"at-least-one-choice","errorCode":null,"errorMessage":"at least one choice","messagePattern":"at least one choice","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"compiler-core/src/exhaustiveness.rs","lineNumber":2646,"sourceCode":"                // matched on then we want to ignore all of those and clump them\n                // into a single \"fallback\" branch to avoid bloating the generated\n                // tree.\n                let mut ignored_checks = vec![];\n                let mut remaining_choices = vec![];\n                for choice in choices.into_iter() {\n                    if choice.0.is_ignored() {\n                        ignored_checks.push(choice.0);\n                    } else {\n                        remaining_choices.push(choice);\n                    }\n                }\n\n                let fallback_check = FallbackCheck::CatchAll { ignored_checks };\n                (remaining_choices, splitter.fallback, fallback_check)\n            } else {\n                // Otherwise we just use the last check as the final one that\n                // can be outright skipped.\n                let (last_check, last_choice) = choices.pop().expect(\"at least one choice\");\n                let fallback_check = FallbackCheck::RuntimeCheck {\n                    check: Box::new(last_check),\n                };\n                (choices, last_choice, fallback_check)\n            };\n\n        let choices = self.compile_all_choices(choices);\n        let fallback = Box::new(self.compile(fallback));\n        Decision::Switch {\n            var,\n            choices,\n            fallback,\n            fallback_check,\n        }\n    }\n\n    fn compile_all_choices(\n        &mut self,","sourceCodeStart":2628,"sourceCodeEnd":2664,"githubUrl":"https://github.com/gleam-lang/gleam/blob/49f8762da595eb3c8f576656a4200a142ca188c9/compiler-core/src/exhaustiveness.rs#L2628-L2664","documentation":"Panic from `choices.pop().expect(\"at least one choice\")` while splitting a decision tree into a final `FallbackCheck::RuntimeCheck`. The algorithm assumes that when there is no catch-all fallback there is at least one remaining choice to promote to the final check; an empty choices vec breaks that invariant.","triggerScenarios":"Compiling a case expression where the choice list for a branch node was fully consumed (or was empty from the start) before this split, e.g. after a bug in overlap removal popped every choice, or a branch reached this code with only a catch-all.","commonSituations":"Compiler developers hit this after modifying how `remaining_choices`/overlaps prune checks, or on pathological case expressions where all checks were deduplicated away.","solutions":["Guard with an explicit `match choices.pop()` and fall back to `FallbackCheck::CatchAll` when the list is empty instead of panicking.","Trace why `choices` is empty: add a debug assert before the split logging the choice count for the failing pattern.","Fix the upstream pruning step so it never removes the last non-catch-all check without producing a catch-all fallback."],"exampleFix":"// before\nlet (last_check, last_choice) = choices.pop().expect(\"at least one choice\");\n// after\nlet Some((last_check, last_choice)) = choices.pop() else {\n    let fallback = FallbackCheck::CatchAll { ignored_checks: Vec::new() };\n    return (choices, splitter.fallback, fallback);\n};","handlingStrategy":"validation","validationCode":"if choices.is_empty() {\n    // use catch-all fallback instead of promoting the last choice\n}","typeGuard":"fn has_final_choice(choices: &[Choice]) -> bool { !choices.is_empty() }","tryCatchPattern":"std::panic::catch_unwind(|| split_node(node)).unwrap_or_else(|_| fallback_to_catch_all(node))","preventionTips":["Ensure overlap pruning never removes the last choice without emitting a catch-all.","Assert choice counts are non-empty at node entry during development.","Add tests for case expressions where all checks get deduplicated away."],"tags":["rust","compiler","panics","exhaustiveness","decision-tree"],"backgroundTag":"empty-required-field","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"}