sqlalchemy/alembic · error · ValueError

Invalid plugin expression

Error message

Invalid plugin expression {name!r}

What it means

Raised as ValueError by _make_re (plugins.py:156-166) when a plugin expression in the include_plugins option contains a token that is neither '*' (wildcard) nor a valid Python identifier. The matcher builds a regex per '.'-separated token; a token with hyphens, spaces, or punctuation fails token.isidentifier() and is rejected. This validates the `alembic include_plugins` config option.

Solutions

  1. Use only valid Python identifiers and '*' in include_plugins, separated by dots (e.g. myplugin or pkg.subplugin or pkg.*).
  2. Remove any hyphens, spaces, or punctuation from the plugin name in alembic.ini.
  3. Confirm the plugin's distribution registers it under the exact identifier you wrote.

Example fix

// before (alembic.ini)
[alembic]
include_plugins = my-plugin
// after
[alembic]
include_plugins = myplugin
Defensive patterns

Strategy: validation

Validate before calling

# Validate an include_plugins expression matches alembic's rules before use.
def valid_plugin_expr(expr: str) -> bool:
    for token in expr.split('.'):
        if token == '*':
            continue
        if not token.isidentifier():
            return False
    return True

for p in include_plugins:
    if not valid_plugin_expr(p):
        raise ValueError(f'Invalid plugin expression {p!r}; use identifiers and * only')

Type guard

def is_valid_plugin_token(token: str) -> bool:
    return token == '*' or token.isidentifier()

Prevention

When it happens

Trigger: Setting include_plugins = bad-name! (or any non-identifier token) in alembic.ini, or passing a malformed plugin glob via the API. Each token must be a Python identifier or '*'.

Common situations: Typos in alembic.ini (e.g. include_plugins = my-plugin with a hyphen); copy-pasting a module path with a stray character; mixing wildcard and identifier syntax incorrectly like myplugin.*.extra.

Related errors


AI-assisted analysis of sqlalchemy/alembic@5551b5d35f (2026-08-11). Data as JSON: /api/errors/a3268d2099d94032. Report an issue: GitHub.

Appendix: 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 5551b5d35f)