python/cpython · error · TypeError
category must be a Warning subclass, not '{type(category).__
Error message
category must be a Warning subclass, not '{type(category).__name__}' What it means
Raised by the pure-Python warnings.warn fallback when the category argument is not a type at all — e.g. a string like 'DeprecationWarning' or an instance like UserWarning('x'). warn() needs a class it can instantiate with the message, so a non-class category fails fast with TypeError. The companion check at the next branch covers classes that are types but not Warning subclasses.
Source
Thrown at Lib/_py_warnings.py:475
while frame is not None and (
_is_internal_filename(filename := frame.f_code.co_filename) or
_is_filename_to_skip(filename, skip_file_prefixes)):
frame = frame.f_back
return frame
# Code typically replaced by _warnings
def warn(message, category=None, stacklevel=1, source=None,
*, skip_file_prefixes=()):
"""Issue a warning, or maybe ignore it or raise an exception."""
# Check if message is already a Warning object
if isinstance(message, Warning):
category = message.__class__
# Check category argument
if category is None:
category = UserWarning
elif not isinstance(category, type):
raise TypeError(f"category must be a Warning subclass, not "
f"'{type(category).__name__}'")
elif not issubclass(category, Warning):
raise TypeError(f"category must be a Warning subclass, not "
f"class '{category.__name__}'")
if not isinstance(skip_file_prefixes, tuple):
# The C version demands a tuple for implementation performance.
raise TypeError('skip_file_prefixes must be a tuple of strs.')
if skip_file_prefixes:
stacklevel = max(2, stacklevel)
# Get context information
try:
if stacklevel <= 1 or _is_internal_frame(sys._getframe(1)):
# If frame is too small to care or if the warning originated in
# internal code, then do not try to hide any frames.
frame = sys._getframe(stacklevel)
else:
frame = sys._getframe(1)
# Look for one frame less since the above line starts us off.View on GitHub (pinned to bc6749cc3b)
Solutions
- Pass the class: warnings.warn('msg', DeprecationWarning)
- Resolve names to classes first: importlib + getattr on the warnings module, then verify it is a Warning subclass
- If the value is already a Warning instance, pass it as the message: warnings.warn(instance) uses its class
Example fix
# before
warnings.warn('feature X is going away', 'DeprecationWarning') # TypeError
# after
warnings.warn('feature X is going away', DeprecationWarning) Defensive patterns
Strategy: type-guard
Validate before calling
import warnings
def warn_with_category(message, category):
if isinstance(message, Warning):
return warnings.warn(message)
if isinstance(category, str):
category = getattr(warnings, category, None) or __import__('builtins').__dict__.get(category)
if not (isinstance(category, type) and issubclass(category, Warning)):
raise TypeError(f'category must be a Warning subclass, got {category!r}')
return warnings.warn(message, category) Type guard
def is_warning_class(cat) -> bool:
return isinstance(cat, type) and issubclass(cat, Warning) Prevention
- Pass Warning classes (DeprecationWarning, UserWarning, ...) — not names, not instances
- If the value is already a Warning instance, pass it as the message: warn(instance)
- Resolve category strings at the config boundary and fail fast there
When it happens
Trigger: warnings.warn('msg', 'DeprecationWarning'); warnings.warn('msg', SomeWarning('extra')); forwarding a category that arrived as text from config/logging records.
Common situations: String category names from log records, serialization layers, or CLI options passed straight to warn; instantiating the category out of habit; dynamically built warn wrappers that lose track of whether they hold a name or a class.
Related errors
- category must be a Warning subclass
- category must be a Warning subclass, not class '{category.__
- invalid action: {action!r}
- message must be a string
- module must be a string
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/82d4e7ea2961cf63.
Report an issue: GitHub.