python/cpython · error · TypeError
Callable must be used as Callable[[arg, ...], result].
Error message
Callable must be used as Callable[[arg, ...], result].
What it means
TypeError raised by collections.abc.CallableType.__new__ (Lib/_collections_abc.py, reached via typing.Callable) when the subscription does not have the two-part shape Callable[[arg, ...], result]. Callable's parameter list must be exactly a 2-tuple: a list of argument types (or ...) followed by the return type, so any other arity or non-tuple argument is rejected.
Source
Thrown at Lib/_collections_abc.py:473
return _check_methods(C, "__buffer__")
return NotImplemented
class _CallableGenericAlias(GenericAlias):
""" Represent `Callable[argtypes, resulttype]`.
This sets ``__args__`` to a tuple containing the flattened
``argtypes`` followed by ``resulttype``.
Example: ``Callable[[int, str], float]`` sets ``__args__`` to
``(int, str, float)``.
"""
__slots__ = ()
def __new__(cls, origin, args):
if not (isinstance(args, tuple) and len(args) == 2):
raise TypeError(
"Callable must be used as Callable[[arg, ...], result].")
t_args, t_result = args
if isinstance(t_args, (tuple, list)):
args = (*t_args, t_result)
elif not _is_param_expr(t_args):
raise TypeError(f"Expected a list of types, an ellipsis, "
f"ParamSpec, or Concatenate. Got {t_args}")
return super().__new__(cls, origin, args)
def __repr__(self):
if len(self.__args__) == 2 and _is_param_expr(self.__args__[0]):
return super().__repr__()
from annotationlib import type_repr
return (f'collections.abc.Callable'
f'[[{", ".join([type_repr(a) for a in self.__args__[:-1]])}], '
f'{type_repr(self.__args__[-1])}]')
def __reduce__(self):View on GitHub (pinned to bc6749cc3b)
Solutions
- Always subscribe with two slots: Callable[[int, str], bool] or Callable[..., None].
- When constructing programmatically, build args as (list_of_params, result) before subscripting.
- Check existing __args__/__parameters__ with typing.get_type_hints or typing.get_args instead of re-assembling aliases by hand.
- For parameterized variants use ParamSpec/Concatenate (e.g. Callable[Concatenate[int, P], R]) which still occupy exactly two slots.
Example fix
# before Handler = typing.Callable[[str, bytes]] # TypeError Run = typing.Callable[int, str, None] # TypeError # after Handler = typing.Callable[[str, bytes], None] Run = typing.Callable[[int, str], None]
Defensive patterns
Strategy: validation
Validate before calling
def callable_args_ok(args) -> bool:
return isinstance(args, tuple) and len(args) == 2
# before dynamic construction:
assert callable_args_ok(params_and_result), f'bad Callable args: {params_and_result!r}' Type guard
import typing
def is_valid_callable_alias(tp) -> bool:
origin = typing.get_origin(tp)
return origin is not None and len(typing.get_args(tp)) in (2,) or (
origin is collections.abc.Callable and len(tp.__args__) >= 2
) Try / catch
try:
Alias = typing.Callable[params, result]
except TypeError as e:
if 'Callable must be used as' in str(e):
raise TypeError(f'fix Callable shape in config: {params!r}') from e
raise Prevention
- Mentor rule: Callable always takes exactly two slots — [params], result.
- Let type checkers (mypy/pyright) catch malformed aliases at lint time.
- For generated annotations, assert the two-tuple shape in tests.
When it happens
Trigger: Writing typing.Callable[[int, str]] (missing the result type), typing.Callable[int, str, None] (three entries), or constructing typing.Callable[...] with a single argument. Building Callable args programmatically with the wrong tuple length hits the same check.
Common situations: Typing beginners omitting the return type; metaprogramming that slices/concatenates __args__ and re-subscribes Callable; copy-paste edits that delete the second element; runtime type inspection code that reconstructs generic aliases.
Related errors
- Expected a list of types, an ellipsis, ParamSpec, or Concate
- module 'collections.abc' has no attribute {attr!r}
- Node can't use cause without an exception.
- coroutine ignored GeneratorExit
- asynchronous generator ignored GeneratorExit
AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14).
Data as JSON: /api/errors/797f1f96818e4cc1.
Report an issue: GitHub.