pytest-dev/pytest · error · TypeError
exceptions must be derived from Warning, not
Error message
exceptions must be derived from Warning, not %s
What it means
Raised by WarningsChecker.__init__ when an element of an expected_warning tuple is not a subclass of Warning. pytest.warns requires warning categories; passing a non-Warning exception type inside the tuple (e.g. ValueError) is a type confusion. The TypeError uses the same 'exceptions must be derived from Warning' template as the single-type check, interpolating type(exc).
Solutions
- Pass only Warning subclasses: pytest.warns((UserWarning, DeprecationWarning)).
- If you intended to assert on exceptions, use pytest.raises((ValueError, RuntimeError)).
- Validate the tuple before passing: assert all(issubclass(c, Warning) for c in cats).
Example fix
// before
with pytest.warns((UserWarning, ValueError)):
...
// after
with pytest.warns((UserWarning, DeprecationWarning)):
...
// if exceptions were intended:
with pytest.raises(ValueError):
... Defensive patterns
Strategy: type-guard
Validate before calling
if isinstance(expected_warning, tuple):
assert all(issubclass(c, Warning) for c in expected_warning), 'all tuple elements must be Warning subclasses' Type guard
def warns_tuple_all_warnings(expected_warning) -> bool:
if not isinstance(expected_warning, tuple):
return True
return all(isinstance(c, type) and issubclass(c, Warning) for c in expected_warning) Prevention
- Pass only Warning subclasses inside the tuple to pytest.warns.
- Keep raises and warns argument lists separate; do not refactor one into the other blindly.
- Add a pre-flight assertion in helpers that build the tuple.
When it happens
Trigger: pytest.warns((UserWarning, ValueError)); pytest.warns((DeprecationWarning, RuntimeError)); any tuple where one element fails issubclass(exc, Warning).
Common situations: Mixing pytest.raises and pytest.warns argument lists; refactoring a raises tuple into warns; passing exception classes by mistake.
Related errors
- Expected , but got
- absolute tolerance for a scalar value must be an int, float…
- approx() is not supported in a boolean context. Did you…
- can only pass None, Path instances or non-empty strings to…
- Cannot enter twice
AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11).
Data as JSON: /api/errors/577b311e374bdb7c.
Report an issue: GitHub.
Appendix: source
Thrown at src/_pytest/recwarn.py:280
@final
class WarningsChecker(WarningsRecorder):
def __init__(
self,
expected_warning: type[Warning] | tuple[type[Warning], ...] = Warning,
match_expr: str | re.Pattern[str] | None = None,
*,
_ispytest: bool = False,
) -> None:
check_ispytest(_ispytest)
super().__init__(_ispytest=True)
msg = "exceptions must be derived from Warning, not %s"
if isinstance(expected_warning, tuple):
for exc in expected_warning:
if not issubclass(exc, Warning):
raise TypeError(msg % type(exc))
expected_warning_tup = expected_warning
elif isinstance(expected_warning, type) and issubclass(
expected_warning, Warning
):
expected_warning_tup = (expected_warning,)
else:
raise TypeError(msg % type(expected_warning))
self.expected_warning = expected_warning_tup
self.match_expr = match_expr
def matches(self, warning: warnings.WarningMessage) -> bool:
assert self.expected_warning is not None
return issubclass(warning.category, self.expected_warning) and bool(
self.match_expr is None or re.search(self.match_expr, str(warning.message))
)
def __exit__(View on GitHub (pinned to 0d6fbdeffa)