{"id":"884cba357d607838","repo":"sqlalchemy/alembic","slug":"can-not-set-dispatch-function-for-object-target-r","errorCode":null,"errorMessage":"Can not set dispatch function for object {target!r}: key already exists. To replace existing function, use replace=True.","messagePattern":"Can not set dispatch function for object (.+?): key already exists\\. To replace existing function, use replace=True\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"alembic/util/langhelpers.py","lineNumber":312,"sourceCode":"\n    LAST = 10\n    \"\"\"Run the function in the last batch of functions\"\"\"\n\n\nclass Dispatcher:\n    def __init__(self) -> None:\n        self._registry: dict[tuple[Any, ...], Any] = {}\n\n    def dispatch_for(\n        self,\n        target: Any,\n        *,\n        qualifier: str = \"default\",\n        replace: bool = False,\n    ) -> Callable[[_C], _C]:\n        def decorate(fn: _C) -> _C:\n            if (target, qualifier) in self._registry and not replace:\n                raise ValueError(\n                    \"Can not set dispatch function for object \"\n                    f\"{target!r}: key already exists. To replace \"\n                    \"existing function, use replace=True.\"\n                )\n            self._registry[(target, qualifier)] = fn\n            return fn\n\n        return decorate\n\n    def dispatch(self, obj: Any, qualifier: str = \"default\") -> Any:\n        if isinstance(obj, str):\n            targets: Sequence[Any] = [obj]\n        elif isinstance(obj, type):\n            targets = obj.__mro__\n        else:\n            targets = type(obj).__mro__\n\n        if qualifier != \"default\":","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/44fb3450330204b222ff05135e1fbbbdb28c44db/alembic/util/langhelpers.py#L294-L330","documentation":"Raised as ValueError by Dispatcher.dispatch_for (langhelpers.py:312) when registering a function for a (target, qualifier) pair that already exists in the registry and replace=False (the default). The dispatcher forbids silent overrides to prevent two plugins/impls from unknowingly clobbering each other's handler for the same type.","triggerScenarios":"Calling dispatcher.dispatch_for(SomeType)(fn) twice; a plugin or impl registering a dispatch for a type that Alembic (or another plugin) already registered; calling dispatch_for on a branched dispatcher that inherited a parent's entry.","commonSituations":"Writing a custom Operations implementation or ddl impl that registers a dispatch for a dialect/type Alembic already handles; loading two plugins that both target the same type; calling dispatch_for in a loop without deduping.","solutions":["If you intend to override, pass replace=True: dispatcher.dispatch_for(SomeType, replace=True)(fn).","Otherwise branch the dispatcher first (dispatcher.branch()) to get an independent writable copy.","Check 'if (target, qualifier) not in dispatcher._registry' before registering to avoid collisions.","Ensure you are not double-loading the same plugin/impl module."],"exampleFix":"# before\nfrom alembic.util.langhelpers import Dispatcher\nd = Dispatcher()\n@d.dispatch_for(int)\ndef h(x): return x\n@d.dispatch_for(int)  # ValueError: key already exists\ndef h2(x): return x*2\n\n# after: explicitly replace\nd.dispatch_for(int, replace=True)\ndef h2(x): return x*2","handlingStrategy":"validation","validationCode":"from alembic.util.langhelpers import Dispatcher\n\ndef safe_register(d: Dispatcher, target, fn, qualifier: str = 'default'):\n    key = (target, qualifier)\n    if key in d._registry:\n        raise ValueError(f'{key} already registered; pass replace=True to override')\n    d.dispatch_for(target, qualifier=qualifier)(fn)","typeGuard":null,"tryCatchPattern":"from alembic.util.langhelpers import Dispatcher\ntry:\n    d.dispatch_for(MyType)(fn)\nexcept ValueError as e:\n    if 'key already exists' in str(e):\n        d.dispatch_for(MyType, replace=True)(fn)\n    else:\n        raise","preventionTips":["Check the registry before registering, or always pass replace=True when overriding is intended.","Use dispatcher.branch() for independent, non-clobbering registries in plugins.","Avoid loading the same impl/plugin module twice."],"tags":["alembic","dispatcher","registration","duplicate","internal-api"],"analyzedSha":"44fb3450330204b222ff05135e1fbbbdb28c44db","analyzedAt":"2026-08-04T19:57:10.248Z","schemaVersion":2}