github/spec-kit · error · IntegrationDescriptorError
Invalid provides.scripts: expected a list
Error message
Invalid provides.scripts: expected a list
What it means
Raised by IntegrationDescriptor._validate() (src/specify_cli/integrations/catalog.py:777) when an integration.yml 'provides' mapping declares 'scripts' with a non-list value. The validator treats provides.scripts as an optional list of relative script path strings; a present-but-wrong-typed value aborts descriptor loading with IntegrationDescriptorError.
Source
Thrown at src/specify_cli/integrations/catalog.py:777
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'"
)
cmd_name = cmd["name"]
cmd_file = cmd["file"]
if not isinstance(cmd_name, str) or not cmd_name.strip():View on GitHub (pinned to bf88c9f9a8)
Solutions
- Change provides.scripts in the offending integration.yml to a YAML list of strings.
- If no scripts are provided, delete the 'scripts' key so the default empty list is used.
- Validate the file again with the catalog loader or the relevant specify command.
Example fix
# before
provides:
scripts: scripts/bash/setup.sh
# after
provides:
scripts:
- scripts/bash/setup.sh Defensive patterns
Strategy: validation
Validate before calling
import yaml
def validate_provides_scripts(path):
data = yaml.safe_load(path.read_text()) or {}
provides = data.get("provides", {})
if "scripts" in provides and not isinstance(provides["scripts"], list):
raise ValueError("provides.scripts must be a list of strings")
return provides.get("scripts", []) Type guard
def is_valid_scripts_list(scripts) -> bool:
return isinstance(scripts, list) and all(
isinstance(s, str) and s.strip() for s in scripts
) Try / catch
try:
desc = IntegrationDescriptor(path)
except IntegrationDescriptorError as e:
if "provides.scripts" in str(e):
fix_scripts_key(path) # rewrite as list or remove key
else:
raise Prevention
- Always write scripts as a YAML list even for a single script.
- Omit the 'scripts' key entirely when there are none.
- Lint descriptors in CI with a small schema validator.
When it happens
Trigger: Loading a descriptor whose 'provides:' block has 'scripts:' set to a scalar, mapping, or null-adjacent value (e.g. 'scripts: setup.sh' instead of a list), causing IntegrationDescriptor(path) to raise during _validate().
Common situations: Authoring provides.scripts as a single path string because the integration has only one script; merging descriptors from a format where scripts were a map of names to paths; YAML flow-syntax mistakes.
Related errors
- Invalid provides.commands: 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/e1355d062f0bc17b.
Report an issue: GitHub.