pytest-dev/pytest · error · TypeError

object (type: ) must be callable

Error message

{func!r} object (type: {type(func)}) must be callable

What it means

Thrown by pytest.raises() in the function-call form when `func` (the second positional argument) is not callable. pytest raises expects a callable to invoke; passing a value, instance, or non-callable object is a misuse.

Solutions

  1. Pass the callable itself, not its result: pytest.raises(ValueError, myfunc) (no parens).
  2. If you need args, use pytest.raises(ValueError, myfunc, arg1, arg2).
  3. Prefer the context-manager form to avoid this footgun: with pytest.raises(ValueError): myfunc(arg1).

Example fix

// before
pytest.raises(ValueError, myfunc())  # calls myfunc first
// after - function form
pytest.raises(ValueError, myfunc, arg1)
// or context-manager form
with pytest.raises(ValueError):
    myfunc(arg1)
Defensive patterns

Strategy: type-guard

Validate before calling

if not callable(func):
    raise TypeError(f'{func!r} is not callable; pass the function, not its result')
pytest.raises(ValueError, func)

Type guard

from collections.abc import Callable
def is_callable_for_raises(func: object) -> bool:
    return callable(func)

Prevention

When it happens

Trigger: Calling pytest.raises(ValueError, 'not a function'); pytest.raises(ValueError, some_object); passing the result of calling a function instead of the function itself: pytest.raises(ValueError, myfunc()).

Common situations: Forgetting to pass the callable (passing its return value); passing a string instead of a function; passing an instance of a non-callable class; copy-paste errors.

Related errors


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

Appendix: source

Thrown at src/_pytest/raises.py:275

    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`
# note: this is *not* the same as `_pytest.main.Failed`
# note: mypy does not recognize this attribute, and it's not possible
#  to use a protocol/decorator like the others in outcomes due to
#  https://github.com/python/mypy/issues/18715
raises.Exception = fail.Exception  # type: ignore[attr-defined]

View on GitHub (pinned to 0d6fbdeffa)