github/spec-kit · error · IntegrationDescriptorError
Invalid provides.commands: expected a list
Error message
Invalid provides.commands: expected a list
What it means
Raised by IntegrationDescriptor._validate() (src/specify_cli/integrations/catalog.py:773) when parsing an integration.yml descriptor whose 'provides' mapping contains a 'commands' key that is not a YAML list. The library enforces a strict schema (schema_version 1.0) so that catalog tooling can rely on provides.commands being iterable. The check only fires when the key is explicitly present; omitting 'commands' entirely defaults it to an empty list.
Source
Thrown at src/specify_cli/integrations/catalog.py:773
if not isinstance(tool, dict):
raise IntegrationDescriptorError(
"Each requires.tools entry must be a mapping"
)
tool_name = tool.get("name")
if not isinstance(tool_name, str) or not tool_name.strip():
raise IntegrationDescriptorError(
"requires.tools entry 'name' must be a non-empty string"
)
provides = self.data["provides"]
if not isinstance(provides, dict):
raise IntegrationDescriptorError(
"'provides' must be a mapping"
)
commands = provides.get("commands", [])
scripts = provides.get("scripts", [])
if "commands" in provides and not isinstance(commands, list):
raise IntegrationDescriptorError(
"Invalid provides.commands: expected a list"
)
if "scripts" in provides and not isinstance(scripts, list):
raise IntegrationDescriptorError(
"Invalid provides.scripts: expected a list"
)
if not commands and not scripts:
raise IntegrationDescriptorError(
"Integration must provide at least one command or script"
)
for cmd in commands:
if not isinstance(cmd, dict):
raise IntegrationDescriptorError(
"Each command entry must be a mapping"
)
if "name" not in cmd or "file" not in cmd:
raise IntegrationDescriptorError(
"Command entry missing 'name' or 'file'"View on GitHub (pinned to bf88c9f9a8)
Solutions
- Open the integration.yml cited by the error and make provides.commands a YAML list of mappings.
- If the integration provides only scripts, remove the 'commands' key entirely so the default [] applies.
- Re-run the descriptor load (or 'specify integration' command) to confirm the error is gone.
Example fix
# before
provides:
commands: plan
# after
provides:
commands:
- name: plan
file: commands/plan.md Defensive patterns
Strategy: validation
Validate before calling
import yaml
def validate_provides_commands(path):
data = yaml.safe_load(path.read_text()) or {}
provides = data.get("provides", {})
if "commands" in provides and not isinstance(provides["commands"], list):
raise ValueError("provides.commands must be a list")
return provides.get("commands", []) Type guard
def is_valid_commands_list(commands) -> bool:
return isinstance(commands, list) and all(
isinstance(c, dict) for c in commands
) Try / catch
from specify_cli.integrations.catalog import IntegrationDescriptor, IntegrationDescriptorError
try:
desc = IntegrationDescriptor(path)
except IntegrationDescriptorError as e:
print(f"Bad descriptor {path}: {e}")
raise SystemExit(1) Prevention
- Start integration.yml from an existing working descriptor and edit incrementally.
- Run a YAML schema check (provides.commands must be a list of mappings) before loading.
- Remember 'commands' is optional — omit it rather than writing a non-list value.
When it happens
Trigger: Constructing IntegrationDescriptor(descriptor_path) (or any catalog load that instantiates it) on an integration.yml where 'provides:' has 'commands:' mapped to a string, mapping, or scalar instead of a list — e.g. 'commands: plan' or 'commands: {name: plan}'.
Common situations: Hand-authoring an integration.yml for a custom integration and writing a single command as a scalar or a mapping instead of a one-element list; copy-pasting from a JSON-style config where the brackets were dropped; YAML indentation collapsing a list into a mapping.
Related errors
- Invalid provides.scripts: expected a list
- Integration must provide at least one command or script
- Each command entry must be a mapping
- Command entry missing 'name' or 'file'
- Command entry 'name' must be a non-empty string
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/8b20d9163aed6034.
Report an issue: GitHub.