MAINT009-missing-default-case — Missing default/wildcard case
| Property | Value |
|---|---|
| Dimension | Maintainability |
| Severity | Medium |
| CWE | CWE-478 |
| Languages | Rust, Python, JavaScript, TypeScript |
What it detects
Flags match/switch constructs that lack a fallback ("default", _) arm when the scrutinee is a value where enumerating all possibilities is unsafe to assume.
- Rust:
matchexpressions where no arm pattern is_(wildcard) and the scrutinee is either a literal (e.g.match 1 { … }) or a lowercase-path expression (heuristic for local variables, not enum variants). - Python:
matchstatements whosecasescontain no irrefutable arm (case _:orcase <name>:). - JS/TS:
switchstatements whosecasescontain nodefault:clause.
Skips (intentional exclusions):
- Rust:
matchexpressions whose scrutinee path ends with an uppercase letter (e.g.match Color::Red { … }) — these are enum matches where the compiler enforces exhaustiveness. - Rust:
matchexpressions whose scrutinee is a call expression, field access, or other non-trivial form — out of scope for this heuristic. - Python:
case _:andcase <name>:are both treated as irrefutable and do not fire.
Why it matters
A switch or match without a default/wildcard arm silently ignores unexpected values. When the set of possible values grows (a new enum variant, an API returning a new status code), the missing branch is never executed — the program continues with undefined or incorrect state (CWE-478). Adding a fallback arm makes the intent explicit and ensures unexpected values are handled, logged, or fail loudly.
Examples — flagged
Python:
match status:
case 1:
handle_ok()
case 2:
handle_error()
# Missing `case _:` — new status codes are silently ignored
Rust:
fn process(code: i32) {
match code {
0 => handle_ok(),
1 => handle_error(),
// Missing `_ => {}` — unexpected codes fall through silently
}
}
JavaScript / TypeScript:
switch (event.type) {
case "click":
onClick();
break;
case "hover":
onHover();
break;
// Missing `default:` — new event types are silently ignored
}
Examples — not flagged
Python (has irrefutable arm):
match status:
case 1:
handle_ok()
case _:
handle_default()
Rust (enum match — compiler checks exhaustiveness):
match color {
Color::Red => {}
Color::Blue => {}
// Compiler error if Color gains a new variant — no finding needed
}
Rust (has wildcard):
match code {
0 => handle_ok(),
_ => handle_unknown(),
}
JS/TS (has default:):
switch (event.type) {
case "click":
onClick();
break;
default:
logUnknown(event.type);
}
Fix guidance
- Add a wildcard/default arm: Use
_ => {}(Rust),case _:(Python), ordefault:(JS/TS). - Fail loudly: Use
_ => unreachable!()(Rust),default: throw new Error(…)(JS/TS), orcase _: raise ValueError(…)(Python) when unexpected values indicate a programming error. - Log and continue: If the new values should be silently ignored for now, add a log statement inside the wildcard arm to record the unexpected input.
Configuration
No configuration knobs in v1. The uppercase-path heuristic for Rust enum exclusion is hardcoded.
Implementation
crates/zuit-lang-rust/src/analyzers/missing_default_case.rscrates/zuit-lang-python/src/analyzers/missing_default_case.rscrates/zuit-lang-js/src/analyzers/missing_default_case.rs