pytest-dev/pytest · error · TypeError
Warning must be str or Warning, got
Error message
Warning must be str or Warning, got {msg!r} (type {type(msg).__name__}) What it means
Raised in WarningsChecker.__exit__ during re-emission of unmatched warnings when a recorded UserWarning's first argument is not a str. CPython's warnings.filterwarnings cannot filter non-str warning messages, producing a confusing error; pytest surfaces it earlier with the actual value and type. It applies only to UserWarning (the default category) whose message args are non-empty and non-str.
Solutions
- Emit warnings with a str message: warnings.warn('deprecated', DeprecationWarning).
- If you need a structured payload, format it to str first: warnings.warn(f'code={code}', UserWarning).
- If the offending emission is in third-party code you cannot change, filter it before pytest.warns runs (e.g. warnings.filterwarnings).
Example fix
// before warnings.warn(response_payload) # response_payload is a dict // after warnings.warn(str(response_payload), UserWarning)
Defensive patterns
Strategy: validation
Validate before calling
import warnings as _w
# before the warned call, ensure callers emit str messages;
# if intercepting, normalize:
orig_warn = _w.warn
def _str_warn(message, *a, **k):
if not isinstance(message, str) and not isinstance(message, Warning):
message = str(message)
return orig_warn(message, *a, **k) Type guard
def warn_message_is_str_or_warning(message) -> bool:
return isinstance(message, (str, Warning)) Prevention
- Always emit warnings with a str message: warnings.warn('text', Category).
- Avoid passing dataclasses/enums/ints as the warning message.
- If third-party code emits non-str UserWarning args, filter it before pytest.warns runs.
When it happens
Trigger: Code under test calls warnings.warn(123) or warnings.warn(some_object) without a category, producing a UserWarning whose message arg is non-str; explicitly emitting UserWarning(non_str).
Common situations: Libraries that pass non-str payloads to warnings.warn (e.g. an error code or dataclass); third-party code emitting UserWarning with structured args; CPython bug workaround per #103577.
Related errors
- Cannot enter twice
- Cannot exit without entering first
- not found in warning list
- exceptions must be derived from Warning, not
- object (type: ) must be callable
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/bb147564fbedcd9f.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/recwarn.py:376
# While this can be considered a bug in CPython, we put guards in
# pytest as the error message produced without this check in place
# is confusing (#10865).
for w in self:
if type(w.message) is not UserWarning:
# If the warning was of an incorrect type then `warnings.warn()`
# creates a UserWarning. Any other warning must have been specified
# explicitly.
continue
if not w.message.args:
# UserWarning() without arguments must have been specified explicitly.
continue
msg = w.message.args[0]
if isinstance(msg, str):
continue
# It's possible that UserWarning was explicitly specified, and
# its first argument was not a string. But that case can't be
# distinguished from an invalid type.
raise TypeError(
f"Warning must be str or Warning, got {msg!r} (type {type(msg).__name__})"
)
View on GitHub (pinned to 0d6fbdeffa)