sqlalchemy/alembic · error · ValueError
A plugin named is already registered
Error message
A plugin named {name} is already registered What it means
Raised as ValueError by Plugin.__init__ (plugins.py:35-40) when a Plugin is constructed with a name that already exists in the module-global _all_plugins dict. Alembic's plugin registry (added in 1.18.0) requires unique names because the autogenerate comparator dispatch keys off them; a duplicate would silently shadow one plugin's comparators.
Solutions
- Uninstall or dedupe the package that registers the duplicate entry point (pip list | grep <plugin>).
- Rename your custom plugin so its name is unique across all installed distributions.
- Call Plugin.remove(name) before re-registering if you intentionally reload a plugin in-process.
Example fix
// before # packageA entry_points: alembic.plugins = myplugin = mypkg.plugin # packageB entry_points: alembic.plugins = myplugin = otherpkg.plugin # collides // after # rename one # packageB entry_points: alembic.plugins = myplugin_v2 = otherpkg.plugin
Defensive patterns
Strategy: validation
Validate before calling
# Detect duplicate plugin entry points before they conflict.
import importlib.metadata as md
from collections import Counter
def find_duplicate_plugins() -> list[str]:
names = [ep.name for ep in md.entry_points(group='alembic.plugins')]
return [n for n, c in Counter(names).items() if c > 1]
dups = find_duplicate_plugins()
if dups:
raise RuntimeError(f'Duplicate alembic plugins registered: {dups}') Type guard
def plugin_name_is_unique(name: str, seen: set[str]) -> bool:
return name not in seen Prevention
- Use unique entry-point names across all installed plugin packages.
- Uninstall superseded plugin packages to remove duplicate dist-info entry points.
- Call Plugin.remove(name) before re-registering in long-lived processes.
When it happens
Trigger: Two installed packages both declaring an `alembic.plugins` entry point with the same name; calling Plugin('myplugin') twice in the same process; registering a plugin that collides with a built-in name.
Common situations: Two virtualenvs merged; a forked/renamed package left behind alongside the new one; reinstalling a plugin package without uninstalling, leaving two dist-info directories publishing the same entry point.
Related errors
- Invalid plugin expression
- Can not set dispatch function for object
- Connection, url, or dialect_name is required.
- No context has been configured yet.
- no dispatch function for object
AI-assisted analysis of sqlalchemy/alembic@5551b5d35f (2026-08-11).
Data as JSON: /api/errors/daa6541c1d1eca29.
Report an issue: GitHub.
Appendix: 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 5551b5d35f)