> ## Content Index
> Fetch the complete content index at: https://debugly.dev/llms.txt
> Use this file to discover other available public pages before exploring further.

# The Enum Case Nobody Handled and the Compiler Did Not Catch
- URL: https://debugly.dev/unhandled-enum-case/
- Published: 2026-10-09T18:40:00.000Z
- Updated: 2026-10-17T05:55:22.000Z
- Description: A new status was added to the model and the match statement had no default, so the new value fell through to the fallback branch, and the order was silently…
- Author: Rohit Bhadani
- Tags: Bug Hunt, Python, Data

It ended at the incident. It started at the completed. Every hand-off in between did exactly what it was told, and this is the one that lied.

Strip the unhandled enum case down and one property makes it silent: the dispatch has a fallback branch, so the new value is handled, and the handling is the wrong behaviour, and the wrong behaviour is the not an error.

I have since met the same mechanics in plenty of language where a match or a switch can omit a case without a compile error.

## Why the new value fell through

The status was the enum, and the enum was the five values, and the five were the handled, and the handled was the dispatch, and the dispatch was the if chain, and the chain was the else, and the else was the fallback, and the fallback was the treat as complete, and the complete was the default's assumption, and the assumption was the safe at the time.

The sixth value was the added, and the added was the partially refunded, and the partially refunded was the not the complete, and the not complete was the unhandled, and the unhandled was the else, and the else was the complete, and the complete was the wrong, and the wrong was the silent, and the silent was the incident.

The fallback was the reasonable when the enum was closed, and the closed was the assumption, and the assumption was the broken by the addition, and the addition was the legitimate, and the legitimate was the not the bug, and the not bug was the dispatch, and the dispatch was the incident's cause, and the cause is the reason the fallback should be the error rather than the behaviour.

## Why nothing caught it

The type checker was the satisfied, and the satisfied was the no exhaustiveness check, and the no check was the runtime's fallback, and the fallback was the no error, and the no error was the test's pass, and the pass was the existing cases, and the existing cases was the not the new, and the not new was the untested, and the untested was the deploy.

The tests covered the five, and the five were the passing, and the passing was the confidence, and the confidence was the merge, and the merge was the production, and the production was the sixth, and the sixth was the incident, and the incident is the reason the enum's addition should force the dispatch's review, and the review is the exhaustive check.

This is the same silent fallback as [the order created hook that fired before the payment cleared](https://debugly.dev/order-hook-fired-before-payment/), and the shared property is the one worth fixing.

## What I changed

**Replaced the fallback with an explicit raise.** The else became the raise on the unknown status, and the raise was the loud, and the loud was the immediate, and the immediate was the fix, and the fix was the one line, and the line was the discipline, because the unknown state should stop the processing rather than guess at it.

**Used a match statement with the exhaustiveness check.** The match was the structural, and the structural was the checker's exhaustiveness, and the exhaustiveness was the missing case's compile error, and the error was the fix, and the fix was the tool, and the tool was the mypy or the pyright, and the checker was the discipline.

**Mapped the dispatch as a dict keyed on the enum.** The dict was the explicit, and the explicit was the missing key's KeyError, and the KeyError was the loud, and the loud was the fix, and the fix was the table, and the table was the discipline, because the table cannot silently accept an unlisted key.

**Added a test that iterates every enum member.** The test was the every value, and the every value was the dispatch's coverage, and the coverage was the new case's automatic inclusion, and the inclusion was the fix, and the fix was the loop, and the loop was the discipline, because the test that lists the cases by hand misses the added one.

**Required the dispatch review when the enum changes.** The change was the pull request's flag, and the flag was the reviewer's attention, and the attention was the catch, and the catch was the prevention, and the prevention was the fix, and the fix was the process, and the process was the discipline.

## If it happens again

A dispatch over an enum with a fallback branch silently does the wrong thing when a new value is added, so the fallback should raise and the dispatch should be exhaustive. Use a match with an exhaustiveness check or a dict keyed on the enum, and write a test that iterates every enum member rather than listing the known cases.

Orders were marked complete without shipping because a new partially refunded status was added to the enum and the status dispatch ended in an else branch that treated anything unrecognised as complete. I now check for that property first, because it is where the failure actually lives.

---

Published on [debugly.dev](https://debugly.dev/) by [Rohit Bhadani](https://debugly.dev/about/) | Founder of [Krova Cloud](https://krova.cloud/?ref=debugly.dev)