pytest-dev/pytest · error · ValueError

Expected , but got

Error message

Expected {expected}, but got {exc.__name__!r}

What it means

Raised by RaisesExc._parse_exc when the exc argument is a class (isinstance(exc, type) is True) but it is neither a BaseException subclass nor a validly-parameterized exception group. It is a defensive ValueError for a path the static type checker marks unreachable — reached only when callers bypass type hints. The message interpolates expected (the human label passed by the caller, e.g. 'a BaseException type') and the offending class name.

Solutions

  1. Pass the actual exception class that derives from BaseException, e.g. pytest.raises(ValueError).
  2. If the value is a group-bearing generic, use the bare group class or RaisesGroup instead of a constrained generic.
  3. Add a runtime assertion before the call: assert isinstance(exc, type) and issubclass(exc, BaseException).

Example fix

// before
with pytest.raises(MyErrorCode):  # MyErrorCode is an IntEnum
    ...
// after
with pytest.raises(MyException):
    ...
// or guard:
assert issubclass(exc_target, BaseException)
with pytest.raises(exc_target):
    ...
Defensive patterns

Strategy: type-guard

Validate before calling

assert isinstance(exc, type) and issubclass(exc, BaseException), f'expected a BaseException type, got {exc!r}'

Type guard

def is_exception_type(exc) -> bool:
    return isinstance(exc, type) and issubclass(exc, BaseException)

Prevention

When it happens

Trigger: Passing a non-exception class such as pytest.raises(int), pytest.raises(dict), or a dataclass type to raises/RaisesExc. Reached only after the earlier BaseException-group branch fails, when the value is a type but issubclass(exc, BaseException) is False.

Common situations: Passing a Pydantic/custom error-code class instead of its raised exception type; refactoring that accidentally substitutes an enum or sentinel class for the exception type; dynamically computed exception arguments that lose their exception-ness.

Related errors


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

Appendix: source

Thrown at src/_pytest/raises.py:451

            ) or (
                issubclass(origin_exc, BaseExceptionGroup)
                and exc_type in (BaseException, Any)
            ):
                if not issubclass(origin_exc, ExceptionGroup):
                    self.is_baseexception = True
                return cast(type[BaseExcT_1], origin_exc)
            else:
                raise ValueError(
                    f"Only `ExceptionGroup[Exception]` or `BaseExceptionGroup[BaseException]` "
                    f"are accepted as generic types but got `{exc}`. "
                    f"As `raises` will catch all instances of the specified group regardless of the "
                    f"generic argument specific nested exceptions has to be checked "
                    f"with `RaisesGroup`."
                )
        # unclear if the Type/ValueError distinction is even helpful here
        msg = f"Expected {expected}, but got "
        if isinstance(exc, type):  # type: ignore[unreachable]
            raise ValueError(msg + f"{exc.__name__!r}")
        if isinstance(exc, BaseException):  # type: ignore[unreachable]
            raise TypeError(msg + f"an exception instance: {type(exc).__name__}")
        raise TypeError(msg + repr(type(exc).__name__))

    @property
    def fail_reason(self) -> str | None:
        """Set after a call to :meth:`matches` to give a human-readable reason for why the match failed.
        When used as a context manager the string will be printed as the reason for the
        test failing."""
        return self._fail_reason

    def _check_check(
        self: AbstractRaises[BaseExcT_1],
        exception: BaseExcT_1,
    ) -> bool:
        if self.check is None:
            return True

View on GitHub (pinned to 0d6fbdeffa)