{"id":"a3268d2099d94032","repo":"sqlalchemy/alembic","slug":"invalid-plugin-expression-name-r","errorCode":null,"errorMessage":"Invalid plugin expression {name!r}","messagePattern":"Invalid plugin expression (.+?)","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"alembic/runtime/plugins.py","lineNumber":166,"sourceCode":"\n        This exact process is invoked automatically at import time for any\n        plugin module that is published via the ``alembic.plugins`` entrypoint.\n\n        \"\"\"\n        module.setup(Plugin(name))\n\n\ndef _make_re(name: str) -> Pattern[str]:\n    tokens = name.split(\".\")\n\n    reg = r\"\"\n    for token in tokens:\n        if token == \"*\":\n            reg += r\"\\..+?\"\n        elif token.isidentifier():\n            reg += r\"\\.\" + token\n        else:\n            raise ValueError(f\"Invalid plugin expression {name!r}\")\n\n    # omit leading r'\\.'\n    return re.compile(f\"^{reg[2:]}$\")\n\n\ndef _setup() -> None:\n    # setup third party plugins\n    for entrypoint in metadata.entry_points(group=\"alembic.plugins\"):\n        for mod in entrypoint.load():\n            Plugin.setup_plugin_from_module(mod, entrypoint.name)\n\n\n_setup()\n","sourceCodeStart":148,"sourceCodeEnd":180,"githubUrl":"https://github.com/sqlalchemy/alembic/blob/44fb3450330204b222ff05135e1fbbbdb28c44db/alembic/runtime/plugins.py#L148-L180","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\ncontext.configure(..., plugins=['my-plugin'])  # raises ValueError\n\n// after\ncontext.configure(..., plugins=['my_plugin'])  # valid identifier","handlingStrategy":"validation","validationCode":"import re\n\ndef is_valid_plugin_expr(expr: str) -> bool:\n    if expr.startswith('~'):\n        expr = expr[1:]\n    for token in expr.split('.'):\n        if token == '*':\n            continue\n        if not token.isidentifier():\n            return False\n    return True","typeGuard":"def is_plugin_expr(expr: str) -> bool:\n    body = expr[1:] if expr.startswith('~') else expr\n    return all(t == '*' or t.isidentifier() for t in body.split('.'))","tryCatchPattern":"try:\n    Plugin.populate_autogenerate_priority_dispatch(comparators, include_plugins=exprs)\nexcept ValueError as e:\n    if 'Invalid plugin expression' in str(e):\n        exprs = [e2 for e2 in exprs if is_valid_plugin_expr(e2)]\n        Plugin.populate_autogenerate_priority_dispatch(comparators, include_plugins=exprs)\n    else:\n        raise","preventionTips":["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."],"tags":["alembic","plugins","configuration","validation"],"analyzedSha":"44fb3450330204b222ff05135e1fbbbdb28c44db","analyzedAt":"2026-08-04T19:57:10.248Z","schemaVersion":2}