sqlalchemy/alembic · error · ValueError

no dispatch function for object: %s

Error message

no dispatch function for object: %s

What it means

Raised as ValueError by Dispatcher.dispatch (langhelpers.py:340) when, after walking the object's MRO (and any fallback qualifiers), no registered function matches any class in the hierarchy. The dispatcher is a type-keyed lookup table; a miss means no handler was ever registered for that type or any of its bases.

Source

Thrown at alembic/util/langhelpers.py:340

    def dispatch(self, obj: Any, qualifier: str = "default") -> Any:
        if isinstance(obj, str):
            targets: Sequence[Any] = [obj]
        elif isinstance(obj, type):
            targets = obj.__mro__
        else:
            targets = type(obj).__mro__

        if qualifier != "default":
            qualifiers = [qualifier, "default"]
        else:
            qualifiers = ["default"]

        for spcls in targets:
            for qualifier in qualifiers:
                if (spcls, qualifier) in self._registry:
                    return self._registry[(spcls, qualifier)]
        else:
            raise ValueError("no dispatch function for object: %s" % obj)

    def branch(self) -> Dispatcher:
        """Return a copy of this dispatcher that is independently
        writable."""

        d = Dispatcher()
        d._registry.update(self._registry)
        return d


class PriorityDispatcher:
    """registers lists of functions at multiple levels of priority and provides
    a target to invoke them in priority order.

    .. versionadded:: 1.18.0 - PriorityDispatcher replaces the job
       of Dispatcher(uselist=True)

    """

View on GitHub (pinned to 44fb345033)

Solutions

  1. Register a dispatch function for the type (or a common base) before calling dispatch: dispatcher.dispatch_for(MyType)(fn).
  2. Upgrade Alembic to a version that supports the construct type produced by your SQLAlchemy version.
  3. Check whether the object's type is what you expect (print type(obj).__mro__) — a wrapper/proxy may hide the real type.
  4. If writing a custom impl, cover the type via dispatch_for on the base class so subclasses resolve too.

Example fix

# before: no handler registered for MyType
dispatcher.dispatch(my_obj)  # ValueError: no dispatch function

# after: register first
@dispatcher.dispatch_for(MyType)
def handle_my_type(obj):
    ...
dispatcher.dispatch(my_obj)
Defensive patterns

Strategy: validation

Validate before calling

from alembic.util.langhelpers import Dispatcher

def has_handler(d: Dispatcher, obj) -> bool:
    targets = [obj] if isinstance(obj, str) else (obj.__mro__ if isinstance(obj, type) else type(obj).__mro__)
    return any((t, 'default') in d._registry for t in targets)

if not has_handler(d, my_obj):
    raise SystemExit(f'No dispatch handler for {type(my_obj)}; register one first')

Try / catch

try:
    result = dispatcher.dispatch(obj)
except ValueError as e:
    if 'no dispatch function' in str(e):
        # register a fallback for the base type, then retry
        dispatcher.dispatch_for(type(obj))(lambda x: None)
        result = dispatcher.dispatch(obj)
    else:
        raise

Prevention

When it happens

Trigger: Calling dispatcher.dispatch(obj) for an object whose type (and all superclasses) have no entry; querying a fresh/empty dispatcher; passing a primitive type (int, str) to a dispatcher that only handles SQLAlchemy construct types.

Common situations: An autogenerate comparison passes an unsupported SQL construct type to a dispatcher that has no impl for it; a custom dialect/impl that did not register handlers for a type autogenerate encounters; upgrading SQLAlchemy which introduces a new construct subclass not yet handled by the Alembic version in use.

Related errors


AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04). Data as JSON: /data/errors/ef145b44511390ae.json. Report an issue: GitHub.