pytest-dev/pytest · error · TypeError
Warning must be str or Warning, got {msg!r} (type {type(msg)
Error message
Warning must be str or Warning, got {msg!r} (type {type(msg).__name__}) What it means
When a recorded warning is a UserWarning whose first argument is not a str, pytest raises TypeError. This guards against calls like warnings.warn(123) that produce warnings CPython cannot filter correctly (see cpython#103577). Warnings must carry a str message or be a proper Warning instance.
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 98b357f69e)
Solutions
- Ensure warnings.warn is called with a str message: warnings.warn('text', Category).
- Wrap non-str values in str() at the call site: warnings.warn(str(obj)).
- If the bad warning comes from a dependency you cannot change, filter or patch it upstream of the pytest.warns block.
- Construct a proper Warning instance with a str arg instead of passing a bare object.
Example fix
// before
import warnings
warnings.warn(123)
// after
import warnings
warnings.warn('123') Defensive patterns
Strategy: validation
Validate before calling
# before emitting, coerce non-str messages to str msg = 123 warnings.warn(str(msg), UserWarning)
Type guard
def is_valid_warning_message(msg) -> TypeGuard[str]:
return isinstance(msg, str) Prevention
- Always call warnings.warn with a str message (or a Warning instance).
- Wrap uncertain values in str() at the warn call site.
- Patch or filter dependencies that emit non-str warnings upstream of pytest.warns blocks.
When it happens
Trigger: Code under test (or a dependency) calls warnings.warn(123), warnings.warn(some_object), or warnings.warn() with a non-str, non-Warning first arg, while inside a pytest.warns/recwarn context. Hits recwarn.py:376 during __exit__ re-emission.
Common situations: Third-party library emits an invalid warning; test helper passes a non-str message; a refactor changed a warning message variable to a non-str type.
Related errors
- exceptions must be derived from Warning, not %s
- Expected {expected}, but got {exc.__name__!r}
- Expected {expected}, but got an exception instance: {type(ex
- Unexpected keyword arguments passed to pytest.warns: {argnam
- {func!r} object (type: {type(func)}) must be callable
AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04).
Data as JSON: /data/errors/bb147564fbedcd9f.json.
Report an issue: GitHub.