github/spec-kit · error · ValueError
Invalid command name {cmd_name!r}: {name_reason}
Error message
Invalid command name {cmd_name!r}: {name_reason} What it means
Before writing any command file, the registrar runs each command name through relative_extension_path_violation(), the shared policy that rejects absolute paths, anchored paths, empty/whitespace names, and '..' traversal. A violating name raises ValueError naming the command and the reason, keeping the runtime guard aligned with ExtensionManifest validation and the skill/preset readers.
Source
Thrown at src/specify_cli/agents.py:696
_sep = agent_config.get("invoke_separator", ".")
registrar_writes_skills = agent_config.get("extension") == "/SKILL.md"
try:
from specify_cli.integrations import get_integration # noqa: PLC0415
_integ = get_integration(agent_name)
if _integ is not None:
_sep = _integ.invoke_separator_for_mode(registrar_writes_skills)
except (ImportError, ValueError, KeyError):
pass
_prefix = get_invocation_prefix(agent_name, registrar_writes_skills)
for cmd_info in commands:
cmd_name = cmd_info["name"]
aliases = cmd_info.get("aliases", [])
cmd_file = cmd_info["file"]
name_reason = relative_extension_path_violation(cmd_name)
if name_reason:
raise ValueError(
f"Invalid command name {cmd_name!r}: {name_reason}"
)
if aliases is None:
aliases = []
if not isinstance(aliases, list):
raise ValueError(
f"Aliases for command {cmd_name!r} must be a list"
)
for alias in aliases:
alias_reason = relative_extension_path_violation(alias)
if alias_reason:
raise ValueError(
f"Invalid command alias {alias!r}: {alias_reason}"
)
# Guard against path traversal using the single shared policy in
# relative_extension_path_violation(), so the runtime guard stays
# aligned with ExtensionManifest._validate() and the skill/presetView on GitHub (pinned to bf88c9f9a8)
Solutions
- Use a flat, relative name: lowercase identifier with no '/', '\', leading '..', or absolute prefix.
- If subdirectories are needed, check whether the target agent supports them at all before encoding paths in the name.
- Validate extension-provided names with the same helper (from specify_cli import relative_extension_path_violation) before calling register.
Example fix
# before
commands = [{"name": "../escape", "file": "plan.md"}]
# after
commands = [{"name": "my-extension-plan", "file": "plan.md"}] Defensive patterns
Strategy: validation
Validate before calling
from specify_cli import relative_extension_path_violation
bad = [c["name"] for c in commands if relative_extension_path_violation(c["name"])]
if bad:
raise SystemExit(f"unsafe command names: {bad}") Type guard
from specify_cli import relative_extension_path_violation
def is_safe_command_name(name: str) -> bool:
"""True when the shared policy finds no path violation in name."""
return relative_extension_path_violation(name) is None Try / catch
try:
registrar.register_commands(...)
except ValueError as exc:
if "Invalid command name" in str(exc):
raise SystemExit(f"rejected unsafe command name: {exc}") from exc
raise Prevention
- Restrict command names to flat lowercase identifiers (letters, digits, '-', '_', '.').
- Run relative_extension_path_violation over extension-provided names in CI.
- Treat this error as a security signal — audit where the name came from, don't just rename.
When it happens
Trigger: A commands list entry with name 'sub/../../cmd', '/etc/cmd', 'cmd/', '' or ' '; names assembled from extension data where user input contains slashes or dot-dot segments.
Common situations: Extension manifests with names containing path separators expecting subdirectories; template-generated names that embed a path; malicious extension content attempting to escape the commands directory. Note: file fields with violations are skipped ('continue'), but name violations are hard errors.
Related errors
- Output path {candidate!r} escapes directory {base!r}
- Invalid command alias {alias!r}: {alias_reason}
- Invalid Copilot prompt name {cmd_name!r}: {name_reason}
- Invalid command 'file' {label}: {reason}
- Invalid {singular} 'file' {label}: {reason}
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/edf382558f8122ed.
Report an issue: GitHub.