Python enum ValueError: is not a valid (tested)
ValueError: 'X' is not a valid MyEnum means MyEnum(x) found no member with that value. We measured the common causes on Python 3.13.5: looking up by name, strings instead of numbers, and case.
1. Status(x) looks up by value, Status[x] by name
from enum import Enum
class Status(Enum):
ACTIVE = 1
BLOCKED = 2
for v in [1, "1", "ACTIVE", 3]:
try:
print(repr(v), "->", Status(v))
except ValueError as e:
print(repr(v), "-> ValueError:", e)
print("by name:", Status["ACTIVE"])
try:
Status["active"]
except KeyError as e:
print("Status['active'] -> KeyError:", e)
Output:
1 -> Status.ACTIVE
'1' -> ValueError: '1' is not a valid Status
'ACTIVE' -> ValueError: 'ACTIVE' is not a valid Status
3 -> ValueError: 3 is not a valid Status
by name: Status.ACTIVE
Status['active'] -> KeyError: 'active'
Measured on Python 3.13.5: calling the enum class, Status(v), matches against member values with no type conversion, so "1" doesn't match 1 and the member name "ACTIVE" doesn't match either. Looking up by name uses square brackets, and a bad name is a KeyError, not a ValueError. Both lookups are case-sensitive.
2. Numbers that arrive as strings
import json
from enum import Enum
class Status(Enum):
ACTIVE = 1
BLOCKED = 2
row = json.loads('{"status": "2"}') # many APIs and CSVs send numbers as strings
try:
Status(row["status"])
except ValueError as e:
print("ValueError:", e)
print(Status(int(row["status"])))
Output:
ValueError: '2' is not a valid Status
Status.BLOCKED
Measured: the error message quotes the value ('2'), which is the clue that a string arrived where the enum has an integer. Convert at the boundary where the data comes in: Status(int(row["status"])).
3. Accept variants with _missing_
from enum import Enum, StrEnum
class Color(StrEnum):
RED = "red"
GREEN = "green"
@classmethod
def _missing_(cls, value): # called only when the plain lookup fails
if isinstance(value, str):
for member in cls:
if member.value == value.strip().lower():
return member
return None # -> the normal ValueError
for v in ["red", " Green ", "RED", "blue"]:
try:
print(repr(v), "->", repr(Color(v)))
except ValueError as e:
print(repr(v), "-> ValueError:", e)
Output:
'red' -> <Color.RED: 'red'>
' Green ' -> <Color.GREEN: 'green'>
'RED' -> <Color.RED: 'red'>
'blue' -> ValueError: 'blue' is not a valid Color
Measured: _missing_ is called only after the normal lookup fails; returning a member accepts the value, returning None gives the usual ValueError. Here it makes lookups case- and whitespace-insensitive while "blue" is still rejected. For enum values that silently become aliases, see our duplicate enum value guide.
Frequently asked questions
What does ValueError: X is not a valid Enum mean?
No member has that value. We measured Status('1'), Status('ACTIVE') and Status(3) all raising it on Python 3.13.5 for an enum with values 1 and 2.
How do I get an enum member by name in Python?
Use square brackets: Status['ACTIVE']. We measured that, and a wrong name raising KeyError instead of ValueError.
Why does my enum fail with a number from JSON or CSV?
The number arrived as a string. We measured Status('2') failing and Status(int('2')) returning Status.BLOCKED.
How do I make enum lookup case-insensitive?
Override the _missing_ classmethod. We measured a StrEnum accepting 'RED' and ' Green ' while still rejecting 'blue'.
Written with AI assistance. Measured on 2026-10-09 with Python 3.13.5: Enum lookups by value and name with ints, numeric strings and names, a JSON string value, and a StrEnum with _missing_. Every block was run verbatim and its output pasted from that run. PlainHeaders is our extension; everything else here is built-in Python.