github/spec-kit · error · BundlerError
Corrupt record: 'contributed_components' must be a list.
Error message
Corrupt record: 'contributed_components' must be a list.
What it means
Raised by InstalledBundleRecord.from_dict when a record's 'contributed_components' key is present but is not a JSON array. The comment documents why: a naive 'or []' would coerce falsy non-lists (0, '', false, {}) to empty and silently accept a corrupt record; only absent/null means 'no components'.
Source
Thrown at src/specify_cli/bundler/models/records.py:65
"version": self.version,
"installed_at": self.installed_at,
"contributed_components": [
_component_to_dict(c) for c in self.contributed_components
],
}
@classmethod
def from_dict(cls, data: Any) -> "InstalledBundleRecord":
if not isinstance(data, dict):
raise BundlerError("Each installed-bundle record must be a mapping.")
components_raw = data.get("contributed_components")
if components_raw is None:
components_raw = []
elif not isinstance(components_raw, list):
# `or []` would coerce a FALSY non-list (0, '', False, {}) to []
# before this guard, silently accepting a corrupt record; only an
# absent/None value means "no components".
raise BundlerError(
"Corrupt record: 'contributed_components' must be a list."
)
bundle_id = str(data.get("bundle_id", "")).strip()
version = str(data.get("version", "")).strip()
if not bundle_id:
raise BundlerError(
"Corrupt records file: an installed-bundle record is missing "
"its 'bundle_id'."
)
if not version:
raise BundlerError(
f"Corrupt records file: record for bundle '{bundle_id}' is "
"missing its 'version'."
)
return cls(
bundle_id=bundle_id,
version=version,
installed_at=str(data.get("installed_at", "")).strip(),View on GitHub (pinned to bf88c9f9a8)
Solutions
- Set 'contributed_components' to an array of component objects (or [] if none).
- Remove the key entirely if there are no contributed components — absence is valid.
Example fix
// before
"contributed_components": "my-skill"
// after
"contributed_components": [
{"kind": "skill", "id": "my-skill", "source": "bundle"}
] Defensive patterns
Strategy: validation
Validate before calling
def components_key_ok(record: dict) -> bool:
c = record.get("contributed_components")
return c is None or isinstance(c, list) Type guard
def is_optional_component_list(raw: object) -> bool:
return raw is None or isinstance(raw, list) Try / catch
try:
records = load_records(project_root)
except BundlerError as e:
if "'contributed_components' must be a list" in str(e):
# fix the record or delete it and reinstall
... Prevention
- 'contributed_components' is an array or absent — never a scalar/bool/object.
- Let the bundler write component lists; manual edits corrupt shape.
When it happens
Trigger: A records-file entry has "contributed_components": "skills" (string), 0, false, or {} instead of an array. from_dict rejects it before building component tuples.
Common situations: Hand-editing the records file to note a component kind as a string; schema drift from older tooling; truncated writes.
Related errors
- Each installed-bundle record must be a mapping.
- Corrupt records file: an installed-bundle record is missing
- Corrupt records file: record for bundle '{bundle_id}' is mis
- Corrupt records file: {path}
- Corrupt records file: {path} — missing 'schema_version'. Exp
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/dddcc900aa8f5370.
Report an issue: GitHub.