Skip to content

prefer-match-assert-never

Typed enum dispatch must not silently ignore unhandled members.

Why

A no-op wildcard or else branch hides missing enum members and lets newly added members pass unnoticed.

Fix

Handle every enum member, bind the catch-all value, and pass it to typing.assert_never; raise an explicit exception when static exhaustiveness is unavailable.

Examples

Before — flagged Closed-set match silently ignores a variant
dispatch.py
from enum import StrEnum
class Kind(StrEnum):
A = "a"
B = "b"
C = "c"
def handle(kind: Kind) -> None:
match kind:
case Kind.A:
handle_a()
case Kind.B:
handle_b()
case _:
pass
After — preferred Closed-set match rejects an unhandled variant
dispatch.py
from enum import StrEnum
from typing import assert_never
class Kind(StrEnum):
A = "a"
B = "b"
C = "c"
def handle(kind: Kind) -> None:
match kind:
case Kind.A:
handle_a()
case Kind.B:
handle_b()
case Kind.C:
handle_c()
case _ as unreachable:
assert_never(unreachable)