sqlalchemy/alembic · error · ValueError
Invalid plugin expression {name!r}
Error message
Invalid plugin expression {name!r} What it means
Raised by _make_re() when parsing a plugin include/exclude expression whose tokens are neither '*' nor valid Python identifiers. Plugin expressions are dot-separated tokens used in include_plugins matching; an invalid character or malformed token makes the expression unusable, so ValueError is raised with the offending expression.
Source
Thrown at alembic/runtime/plugins.py:166
This exact process is invoked automatically at import time for any
plugin module that is published via the ``alembic.plugins`` entrypoint.
"""
module.setup(Plugin(name))
def _make_re(name: str) -> Pattern[str]:
tokens = name.split(".")
reg = r""
for token in tokens:
if token == "*":
reg += r"\..+?"
elif token.isidentifier():
reg += r"\." + token
else:
raise ValueError(f"Invalid plugin expression {name!r}")
# omit leading r'\.'
return re.compile(f"^{reg[2:]}$")
def _setup() -> None:
# setup third party plugins
for entrypoint in metadata.entry_points(group="alembic.plugins"):
for mod in entrypoint.load():
Plugin.setup_plugin_from_module(mod, entrypoint.name)
_setup()
View on GitHub (pinned to 44fb345033)
Solutions
- Use only valid Python identifiers and '*' wildcards, dot-separated (e.g. 'mypkg.*', '~mypkg.experimental').
- Prefix-include/exclude with '~' for exclusion and '*' as a wildcard segment.
- Verify the 'plugins' option in env.py / configure() against the documented grammar.
Example fix
// before context.configure(..., plugins=['my-plugin']) # raises ValueError // after context.configure(..., plugins=['my_plugin']) # valid identifier
Defensive patterns
Strategy: validation
Validate before calling
import re
def is_valid_plugin_expr(expr: str) -> bool:
if expr.startswith('~'):
expr = expr[1:]
for token in expr.split('.'):
if token == '*':
continue
if not token.isidentifier():
return False
return True Type guard
def is_plugin_expr(expr: str) -> bool:
body = expr[1:] if expr.startswith('~') else expr
return all(t == '*' or t.isidentifier() for t in body.split('.')) Try / catch
try:
Plugin.populate_autogenerate_priority_dispatch(comparators, include_plugins=exprs)
except ValueError as e:
if 'Invalid plugin expression' in str(e):
exprs = [e2 for e2 in exprs if is_valid_plugin_expr(e2)]
Plugin.populate_autogenerate_priority_dispatch(comparators, include_plugins=exprs)
else:
raise Prevention
- Use only Python identifiers and '*' wildcards in plugin expressions.
- Validate plugin expressions before passing them to configure().
- Avoid hyphens/spaces in plugin names; prefer dotted identifiers.
When it happens
Trigger: Passing an invalid plugin expression to Plugin.populate_autogenerate_priority_dispatch(..., include_plugins=[...]) such as 'my-plugin' (hyphen), 'my plugin' (space), 'my!plugin', or a token starting with a digit; misconfiguring the 'plugins' option in env.py.
Common situations: Typing a plugin name with hyphens or spaces in the alembic 'plugins' config option; copy-pasting a package name (with hyphens) as a plugin expression instead of the dotted module path.
Related errors
- A plugin named {name} is already registered
- recreate may be one of 'auto', 'always', or 'never'.
- 'type' can be one of %s
- No context has been configured yet.
- Connection, url, or dialect_name is required.
AI-assisted analysis of sqlalchemy/alembic@44fb345033 (2026-08-04).
Data as JSON: /data/errors/a3268d2099d94032.json.
Report an issue: GitHub.