pytest-dev/pytest · error · TypeError

exceptions must be derived from Warning, not %s

Error message

exceptions must be derived from Warning, not %s

What it means

In WarningsChecker, every element of a tuple passed as expected_warning must be a subclass of Warning. Passing a non-Warning type (e.g. an exception class) in the tuple is rejected.

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 98b357f69e)

Solutions

  1. Use only Warning subclasses in the tuple: pytest.warns((UserWarning, RuntimeWarning)).
  2. Verify each element with issubclass(x, Warning) before passing when constructed dynamically.
  3. Remember warns is for warnings (Warning subclasses), raises is for exceptions (BaseException subclasses).

Example fix

// before
pytest.warns((UserWarning, ValueError))
// after
pytest.warns((UserWarning, RuntimeWarning))
Defensive patterns

Strategy: type-guard

Validate before calling

for exc in expected_warning:
    if not (isinstance(exc, type) and issubclass(exc, Warning)):
        raise TypeError(f'{exc!r} is not a Warning subclass')
pytest.warns(expected_warning)

Type guard

def all_are_warning_types(excs) -> TypeGuard[tuple[type[Warning], ...]]:
    return isinstance(excs, tuple) and all(isinstance(e, type) and issubclass(e, Warning) for e in excs)

Prevention

When it happens

Trigger: Calling pytest.warns((UserWarning, ValueError)) — ValueError is an exception, not a Warning. Hits recwarn.py:280 inside the tuple loop.

Common situations: Mixing exception classes with warning classes; typo; assuming warns accepts exception types like raises does.

Related errors


AI-assisted analysis of pytest-dev/pytest@98b357f69e (2026-08-04). Data as JSON: /data/errors/577b311e374bdb7c.json. Report an issue: GitHub.