pytest-dev/pytest · error · ValueError

Expected an exception type or a tuple of exception types, bu

Error message

Expected an exception type or a tuple of exception types, but got `{expected_exception!r}`. Raising exceptions is already understood as failing the test, so you don't need any special code to say 'this should never raise an exception'.

What it means

Raised by the function-call form of pytest.raises when the first positional argument (expected_exception) is falsy. pytest already treats any uncaught exception as a test failure, so there is no 'assert it does not raise' mode via raises. Passing None/empty here is a misuse of the API.

Source

Thrown at src/_pytest/raises.py:269

        frame) alive until the next cyclic garbage collection run.
        More detailed information can be found in the official Python
        documentation for :ref:`the try statement <python:try>`.
    """
    __tracebackhide__ = True

    if func is None and not args:
        if set(kwargs) - {"match", "check", "expected_exception"}:
            msg = "Unexpected keyword arguments passed to pytest.raises: "
            msg += ", ".join(sorted(kwargs))
            msg += "\nUse context-manager form instead?"
            raise TypeError(msg)

        if expected_exception is None:
            return RaisesExc(**kwargs)
        return RaisesExc(expected_exception, **kwargs)

    if not expected_exception:
        raise ValueError(
            f"Expected an exception type or a tuple of exception types, but got `{expected_exception!r}`. "
            f"Raising exceptions is already understood as failing the test, so you don't need "
            f"any special code to say 'this should never raise an exception'."
        )
    if not callable(func):
        raise TypeError(f"{func!r} object (type: {type(func)}) must be callable")
    with RaisesExc(expected_exception) as excinfo:
        func(*args, **kwargs)
    try:
        return excinfo
    finally:
        del excinfo


# note: RaisesExc/RaisesGroup uses fail() internally, so this alias
#  indicates (to [internal] plugins?) that `pytest.raises` will
#  raise `_pytest.outcomes.Failed`, where
#  `outcomes.Failed is outcomes.fail.Exception is raises.Exception`

View on GitHub (pinned to 98b357f69e)

Solutions

  1. Remove the pytest.raises wrapper entirely — a test that should not raise simply runs the code directly; an unexpected exception already fails the test.
  2. If you conditionally expect no exception, branch on the parametrized value and only wrap when an exception type is present.
  3. If you need an explicit 'did not raise' assertion, use try/except around the call with pytest.fail('unexpectedly raised') in the except block.
  4. Audit the parametrize table / variable source feeding expected_exception to ensure it is never None or empty when reaching raises.

Example fix

// before
pytest.raises(maybe_none_exc, my_func)
// after
if maybe_none_exc is not None:
    with pytest.raises(maybe_none_exc):
        my_func()
else:
    my_func()
Defensive patterns

Strategy: validation

Validate before calling

if not expected_exception:
    raise ValueError('expected_exception must be a non-empty exception type or tuple')
# only then:
pytest.raises(expected_exception, func)

Type guard

def is_valid_expected(exc) -> bool:
    return bool(exc) and (
        isinstance(exc, type) and issubclass(exc, BaseException)
        or isinstance(exc, tuple) and all(isinstance(e, type) and issubclass(e, BaseException) for e in exc)
    )

Prevention

When it happens

Trigger: Calling pytest.raises(None, my_func), pytest.raises((), my_func), or pytest.raises(0, my_func) — i.e. the function-call form (raises(exc, func)) where exc evaluates to a falsy value. Hits the branch at raises.py:268 (`if not expected_exception:`).

Common situations: A parametrized variable intended to hold an exception class is None for some parameter combo; a refactor leaves a stale variable; or a developer misunderstands raises as a 'should not raise' assertion.

Related errors


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