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

  1. Always subscribe with two slots: Callable[[int, str], bool] or Callable[..., None].
  2. When constructing programmatically, build args as (list_of_params, result) before subscripting.
  3. Check existing __args__/__parameters__ with typing.get_type_hints or typing.get_args instead of re-assembling aliases by hand.
  4. 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

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


AI-assisted analysis of python/cpython@bc6749cc3b (2026-08-14). Data as JSON: /api/errors/797f1f96818e4cc1. Report an issue: GitHub.