github/spec-kit · error · ValidationError
Invalid command name '{cmd['name']}': must follow pattern 's
Error message
Invalid command name '{cmd['name']}': must follow pattern 'speckit.{extension}.{command}' What it means
A command name did not match the required pattern ^speckit\.([a-z0-9-]+)\.([a-z0-9-]+)$ (EXTENSION_COMMAND_NAME_PATTERN, extensions/__init__.py:62) AND the loader could not auto-correct it via _try_correct_command_name(). The auto-corrector fixes two legacy forms — 'speckit.command' → 'speckit.{ext_id}.command' and '{ext_id}.command' → 'speckit.{ext_id}.command' — so only names outside those salvageable formats reach this hard error. This is a manifest-authoring contract: all extension commands live in the speckit.{extension}.{command} namespace.
Source
Thrown at src/specify_cli/extensions/__init__.py:485
cmd_file = cmd["file"]
reason = relative_extension_path_violation(cmd_file)
if reason:
label = repr(cmd_file) if isinstance(cmd_file, str) else f"for command '{cmd.get('name')}'"
raise ValidationError(f"Invalid command 'file' {label}: {reason}")
# Validate command name format
if not EXTENSION_COMMAND_NAME_PATTERN.match(cmd["name"]):
corrected = self._try_correct_command_name(cmd["name"], ext["id"])
if corrected:
self.warnings.append(
f"Command name '{cmd['name']}' does not follow the required pattern "
f"'speckit.{{extension}}.{{command}}'. Registering as '{corrected}'. "
f"The extension author should update the manifest to use this name."
)
rename_map[cmd["name"]] = corrected
cmd["name"] = corrected
else:
raise ValidationError(
f"Invalid command name '{cmd['name']}': "
"must follow pattern 'speckit.{extension}.{command}'"
)
# Validate alias types; no pattern enforcement on aliases — they are
# intentionally free-form to preserve community extension compatibility
# (e.g. 'speckit.verify' short aliases used by existing extensions).
aliases = cmd.get("aliases")
if aliases is None:
cmd["aliases"] = []
aliases = []
if not isinstance(aliases, list):
raise ValidationError(
f"Aliases for command '{cmd['name']}' must be a list"
)
for alias in aliases:
if not isinstance(alias, str):
raise ValidationError(View on GitHub (pinned to bf88c9f9a8)
Solutions
- Rename the command in the manifest to 'speckit.<your-extension-id>.<lowercase-slug>', e.g. "speckit.myext.build".
- Keep every segment lowercase alphanumeric plus hyphens; use hyphens not underscores.
- If you intended a short alias like 'speckit.verify', keep the canonical three-part name and declare the short form under 'aliases' instead (aliases are free-form).
Example fix
// before
{ "name": "build", "file": "commands/build.md" }
// after
{ "name": "speckit.myext.build", "file": "commands/build.md", "aliases": ["build"] } Defensive patterns
Strategy: validation
Validate before calling
import re
PATTERN = re.compile(r"^speckit\.([a-z0-9-]+)\.([a-z0-9-]+)$")
bad = [c["name"] for c in manifest["provides"]["commands"]
if "name" in c and isinstance(c["name"], str) and not PATTERN.match(c["name"])]
assert not bad, f"non-conforming command names (not auto-correctable?): {bad}" Type guard
def is_canonical_command_name(name: str, ext_id: str) -> bool:
import re
return bool(re.match(r"^speckit\.[a-z0-9-]+\.[a-z0-9-]+$", name)) and name.split(".")[1] == ext_id Try / catch
try:
ExtensionManifest.load(path)
except ValidationError as e:
if "must follow pattern 'speckit" in str(e):
# rename to speckit.<ext-id>.<slug>; note typos may be auto-corrected with a warning instead
... Prevention
- Name every command speckit.<extension-id>.<lowercase-slug> from the start.
- Use hyphens, never underscores or uppercase, in command segments.
- Put short forms in 'aliases', not the primary name.
When it happens
Trigger: Declaring a command named "build", "myext:build", "speckit.MyExt.Build" (uppercase), "speckit.myext.sub.build" (three segments), or "speckit.otherext.build" (wrong extension id that correction cannot derive). The pattern check runs after the rename-map pass in ExtensionManifest._validate().
Common situations: Porting a community extension authored before the namespacing rule; using uppercase or underscore-separated command slugs; copy-pasting a command name from a different extension and forgetting to change the middle segment.
Related errors
- Invalid {singular} name '{name}': must be lowercase alphanum
- Extension ID '{manifest.id}' conflicts with core command nam
- Manifest must be a YAML mapping, got {type(data).__name__}:
- Missing required field: {field}
- Invalid extension: expected a mapping, got {type(ext).__name
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/99a79fa3735afe4c.
Report an issue: GitHub.