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/preset

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Use a flat, relative name: lowercase identifier with no '/', '\', leading '..', or absolute prefix.
  2. If subdirectories are needed, check whether the target agent supports them at all before encoding paths in the name.
  3. 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

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


AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14). Data as JSON: /api/errors/edf382558f8122ed. Report an issue: GitHub.