ImportError: cannot import name 'StrEnum' from 'enum' (tested fix)

ImportError: cannot import name 'StrEnum' from 'enum' means the code runs on Python 3.10 or older; StrEnum arrived in 3.11. We tested the import, the usual (str, Enum) replacement and a fallback on Python 3.8, 3.11 and 3.13.

1. StrEnum only exists in Python 3.11+

import sys
print(sys.version.split()[0])
try:
    from enum import StrEnum
    print("ok:", StrEnum)
except ImportError as e:
    print(f"{type(e).__name__}: {e}")

Output on the official python:3.8-alpine image:

3.8.20
ImportError: cannot import name 'StrEnum' from 'enum' (/usr/local/lib/python3.8/enum.py)

Output on Python 3.13.5:

3.13.5
ok: <enum 'StrEnum'>

enum.StrEnum was added in Python 3.11. On 3.10 and older the import fails. Check python3 --version where the error happens (server, Docker image, CI runner); it is often older than your own machine.

2. Fix: subclass str and Enum

from enum import Enum

class Color(str, Enum):           # works on every Python 3
    RED = "red"
    BLUE = "blue"

print(Color.RED == "red", Color("blue"))
print(Color.RED.value, f"{Color.RED.value}")

Output:

True Color.BLUE
red red

Same output on 3.8. Members compare equal to plain strings, and .value is the string.

3. Gotcha: str() and f-strings of a (str, Enum) member

import sys
from enum import Enum
class A(str, Enum):
    RED = "red"
print(sys.version.split()[0], "|", str(A.RED), "|", f"{A.RED}", "|", "%s" % A.RED)

Output on 3.13.5, 3.8.20 and 3.11.17:

3.13.5 | A.RED | A.RED | A.RED
3.8.20 | A.RED | red | A.RED
3.11.17 | A.RED | A.RED | A.RED

str() gives A.RED, not red, on every version. The f-string result changed in 3.11: on 3.8 it gave red, on 3.11+ it gives A.RED. If you upgrade Python with a (str, Enum) class, f-strings that built URLs, file names or SQL from members silently change. StrEnum gives red for both:

from enum import Enum, StrEnum
class A(str, Enum):
    RED = "red"
class B(StrEnum):
    RED = "red"
print(str(A.RED), f"{A.RED}", "|", str(B.RED), f"{B.RED}")

Output:

A.RED A.RED | red red

4. Fix for code that must run on old and new Python

from enum import Enum
try:
    from enum import StrEnum
except ImportError:               # Python < 3.11
    class StrEnum(str, Enum):
        def __str__(self):
            return self.value

class Color(StrEnum):
    RED = "red"

print(Color.RED == "red", str(Color.RED), f"{Color.RED}")

Output:

True red red

We ran this block unchanged on 3.8 and 3.13; both printed the line above. The __str__ override makes the fallback behave like the real StrEnum for str() and f-strings. (The real one also adds auto() producing the lower-case member name; in the fallback auto() gives '1' on 3.13, so give explicit values.)

Related: ImportError: cannot import name and cannot import name 'UTC' from 'datetime' (also new in 3.11).

Frequently asked questions

Why can't I import StrEnum from enum?

enum.StrEnum was added in Python 3.11. On 3.10 and older it does not exist.

What can I use instead of StrEnum?

class Color(str, Enum). Add def __str__(self): return self.value if you need str() and f-strings to give the value.

Why does my (str, Enum) f-string print Color.RED?

Since Python 3.11, format() of a mixed-in str Enum uses the enum's str(), which is Color.RED. On 3.8 it gave the value.

Written with AI assistance. Measured on 2026-10-22 with Python 3.13.5 on Debian and the official python:3.8-alpine (3.8.20) and python:3.11-alpine (3.11.17) images: importing StrEnum, a (str, Enum) class, str()/f-string/% formatting of members, and a try/except fallback. Every block was run verbatim and its output pasted unedited. PlainHeaders is our extension; Python is free.