pytest-dev/pytest · error · AssertionError

not found in warning list

Error message

{cls!r} not found in warning list

What it means

Raised by WarningsRecorder.pop when no recorded warning matches the requested category cls. pop searches for an exact category match first, then the most-derived subclass match; if neither is found it raises AssertionError. This signals a test expectation failure: the user asked for a warning of that category that was never emitted.

Solutions

  1. Check membership before popping: if any(w.category is cls for w in recorder): recorder.pop(cls).
  2. Use pytest.warns(ExpectedCategory) at the assertion level rather than manual pop, so pytest reports DID NOT WARN with context.
  3. Inspect recorder.list to see what was actually emitted and correct the expected category.

Example fix

// before
warn = recorder.pop(DeprecationWarning)  # AssertionError if absent
// after
matches = [w for w in recorder if issubclass(w.category, DeprecationWarning)]
assert matches, f'no DeprecationWarning; got {[w.category.__name__ for w in recorder]}'
warn = matches[0]
Defensive patterns

Strategy: try-catch

Validate before calling

matches = [w for w in recorder if issubclass(w.category, cls)]
assert matches, f'{cls!r} not in {[w.category.__name__ for w in recorder]}'
warn = matches[0]

Type guard

def recorder_has_category(recorder, cls) -> bool:
    return any(issubclass(w.category, cls) for w in recorder)

Try / catch

try:
    warn = recorder.pop(cls)
except AssertionError:
    # handle missing-warning expectation explicitly
    raise AssertionError(f'expected {cls}; got {[w.category.__name__ for w in recorder]}')

Prevention

When it happens

Trigger: Calling recorder.pop(UserWarning) or pop(DeprecationWarning) when the recorded list contains no warning of that category. Reached when best_idx stays None after the loop.

Common situations: Inspecting a WarningsRecorder/pytest.warns result and popping a category the code under test did not emit; ordering bugs where pop is called twice for the same warning; mismatched category assumptions after a refactor.

Related errors


AI-assisted analysis of pytest-dev/pytest@0d6fbdeffa (2026-08-11). Data as JSON: /api/errors/b90cdefc6a9095d8. Report an issue: GitHub.

Appendix: source

Thrown at src/_pytest/recwarn.py:228

    def pop(self, cls: type[Warning] = Warning) -> warnings.WarningMessage:
        """Pop the first recorded warning which is an instance of ``cls``,
        but not an instance of a child class of any other match.
        Raises ``AssertionError`` if there is no match.
        """
        best_idx: int | None = None
        for i, w in enumerate(self._list):
            if w.category == cls:
                return self._list.pop(i)  # exact match, stop looking
            if issubclass(w.category, cls) and (
                best_idx is None
                or not issubclass(w.category, self._list[best_idx].category)
            ):
                best_idx = i
        if best_idx is not None:
            return self._list.pop(best_idx)
        __tracebackhide__ = True
        raise AssertionError(f"{cls!r} not found in warning list")

    def clear(self) -> None:
        """Clear the list of recorded warnings."""
        self._list[:] = []

    # Type ignored because we basically want the `catch_warnings` generic type
    # parameter to be ourselves but that is not possible(?).
    def __enter__(self) -> Self:  # type: ignore[override]
        if self._entered:
            __tracebackhide__ = True
            raise RuntimeError(f"Cannot enter {self!r} twice")
        _list = super().__enter__()
        # record=True means it's None.
        assert _list is not None
        self._list = _list
        warnings.simplefilter("always")
        return self

View on GitHub (pinned to 0d6fbdeffa)