sqlalchemy/alembic · error · ValueError
A plugin named {name} is already registered
Error message
A plugin named {name} is already registered What it means
Raised by Plugin.__init__() when a Plugin with the given name already exists in the global _all_plugins registry. Plugin names must be unique process-wide because the autogenerate comparator dispatch and branch-label mapping key off them. The check runs at construction, which happens automatically for any module published via the alembic.plugins entry point and on manual Plugin() creation.
Source
Thrown at alembic/runtime/plugins.py:39
log = logging.getLogger(__name__)
class Plugin:
"""Describe a series of functions that are pulled in as a plugin.
This is initially to provide for portable lists of autogenerate
comparison functions, however the setup for a plugin can run any
other kinds of global registration as well.
.. versionadded:: 1.18.0
"""
def __init__(self, name: str):
self.name = name
log.info("setup plugin %s", name)
if name in _all_plugins:
raise ValueError(f"A plugin named {name} is already registered")
_all_plugins[name] = self
self.autogenerate_comparators = PriorityDispatcher()
def remove(self) -> None:
"""remove this plugin"""
del _all_plugins[self.name]
def add_autogenerate_comparator(
self,
fn: Callable[..., PriorityDispatchResult],
compare_target: str,
compare_element: str | None = None,
*,
qualifier: str = "default",
priority: DispatchPriority = DispatchPriority.MEDIUM,
) -> None:
"""Register an autogenerate comparison function.View on GitHub (pinned to 44fb345033)
Solutions
- Give each plugin a unique entry point / Plugin() name (namespace with package prefix).
- In test teardown call plugin.remove() to deregister before re-registering.
- Audit installed packages' alembic.plugins entry points and rename the duplicate.
Example fix
// before
# two packages both declare entry point name 'myplugin'
Plugin('myplugin') # second call raises ValueError
// after
# give unique names
Plugin('pkg_a.myplugin')
Plugin('pkg_b.myplugin') Defensive patterns
Strategy: validation
Validate before calling
from alembic.runtime.plugins import _all_plugins
def plugin_name_available(name) -> bool:
return name not in _all_plugins Try / catch
from alembic.runtime.plugins import Plugin, _all_plugins
try:
Plugin(name)
except ValueError as e:
if 'already registered' in str(e):
existing = _all_plugins[name]
existing.remove()
Plugin(name)
else:
raise Prevention
- Namespace plugin names by package to avoid collisions.
- Call plugin.remove() in test teardown.
- Audit installed alembic.plugins entry points for duplicate names.
When it happens
Trigger: Two installed packages declaring the same alembic.plugins entry point name; manually calling Plugin('name') twice; an entry point and a manual registration both using 'name'; re-importing a plugin module after a failed remove() in a long-lived process or test session.
Common situations: Two third-party libraries shipping alembic plugins under the same entry point name; a plugin left in _all_plugins between tests because remove() wasn't called; a local plugin whose name collides with a published one.
Related errors
- Invalid plugin expression {name!r}
- No context has been configured yet.
- Connection, url, or dialect_name is required.
- Cycle is detected in revisions (%s)
- Branch name '%s' in revision %s already used by revision %s
AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04).
Data as JSON: /data/errors/daa6541c1d1eca29.json.
Report an issue: GitHub.