github/spec-kit · error · ValidationError

Aliases for command '{cmd['name']}' must be a list

Error message

Aliases for command '{cmd['name']}' must be a list

What it means

A provides.commands entry declared 'aliases' with a value that is not a YAML/JSON list (e.g. a bare string or mapping). Aliases are optional (missing/null normalizes to []), but when present they must be a list; the manifest loader raises ValidationError before any alias content is examined. Note aliases are intentionally free-form strings (no speckit.* pattern enforced) to keep community extensions working.

Source

Thrown at src/specify_cli/extensions/__init__.py:498

                        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(
                        f"Aliases for command '{cmd['name']}' must be strings"
                    )
                alias_reason = relative_extension_path_violation(alias)
                if alias_reason:
                    raise ValidationError(
                        f"Invalid alias {alias!r} for command "
                        f"'{cmd['name']}': {alias_reason}"
                    )

        # Rewrite any hook command references that pointed at a renamed command or
        # an alias-form ref (ext.cmd → speckit.ext.cmd).  Always emit a warning when
        # the reference is changed so extension authors know to update the manifest.
        for hook_name, hook_data in self.data.get("hooks", {}).items():

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Wrap the alias(es) in a list: "aliases": ["build"].
  2. If no aliases are wanted, remove the key entirely (it defaults to []).
  3. Ensure YAML/JSON serialization of generated manifests always emits arrays for aliases.

Example fix

// before
"aliases": "build"
// after
"aliases": ["build"]
Defensive patterns

Strategy: validation

Validate before calling

for c in manifest.get("provides", {}).get("commands", []):
    if "aliases" in c and c["aliases"] is not None and not isinstance(c["aliases"], list):
        raise SystemExit(f"aliases for {c.get('name')} must be a list")

Type guard

def has_list_aliases(cmd: dict) -> bool:
    a = cmd.get("aliases")
    return a is None or isinstance(a, list)

Try / catch

try:
    ExtensionManifest.load(path)
except ValidationError as e:
    if "must be a list" in str(e):
        # wrap the aliases value in [ ... ] and retry
        ...

Prevention

When it happens

Trigger: "aliases": "build" (bare string), "aliases": {"short": "build"} (mapping), or "aliases": 3. Occurs while iterating commands during ExtensionManifest._validate().

Common situations: Author used a single string because there is only one alias; YAML folding a one-element flow into a scalar; copy-pasting from a docs example that shows the alias name instead of a list.

Related errors


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