github/spec-kit · error · BundlerError
Corrupt records file: {path}
Error message
Corrupt records file: {path} What it means
Raised by load_records when the installed-bundles records file parses to a non-object JSON value at the top level (e.g. an array or bare string). The reader needs a mapping to extract 'schema_version' and 'bundles'; anything else is treated as corruption with the path in the message. Note the read path is also confined via ensure_within, refusing symlinked or traversal-escaping .specify paths.
Source
Thrown at src/specify_cli/bundler/models/records.py:127
seen = str(value).strip()
if seen.split(".")[0] != RECORDS_SCHEMA_VERSION.split(".")[0]:
raise BundlerError(
f"Unsupported records schema version '{seen}' at {path}; this "
f"Spec Kit understands version {RECORDS_SCHEMA_VERSION}. The file may "
"have been written by a newer version or is corrupt."
)
def load_records(project_root: Path) -> list[InstalledBundleRecord]:
# Defense in depth (mirrors the write path's within= confinement): refuse to
# read through a symlinked or traversal-escaping ``.specify`` that resolves
# outside project_root.
path = ensure_within(project_root, records_path(project_root))
if not path.exists():
return []
data = load_json(path)
if not isinstance(data, dict):
raise BundlerError(f"Corrupt records file: {path}")
_check_schema_version(data.get("schema_version"), path=path, required=True)
bundles = data.get("bundles")
if bundles is None:
bundles = []
elif not isinstance(bundles, list):
# `or []` would coerce a FALSY non-list (0, '', False, {}) to [] before
# this guard, silently treating a corrupt file as "no bundles"; only an
# absent/None value means empty.
raise BundlerError(
f"Corrupt records file: {path} — 'bundles' must be a list."
)
return [InstalledBundleRecord.from_dict(item) for item in bundles]
def save_records(project_root: Path, records: list[InstalledBundleRecord]) -> None:
payload = {
"schema_version": RECORDS_SCHEMA_VERSION,
"updated_at": _utc_now(),View on GitHub (pinned to bf88c9f9a8)
Solutions
- Wrap the content in a top-level object: {"schema_version": "1", "bundles": [...]}.
- If content integrity is doubtful, delete the file and reinstall bundles — load_records returns [] for a missing file.
- Check for symlinks under .specify pointing outside the project if the path in the message looks unexpected.
Example fix
// before (installed-bundles.json)
[
{"bundle_id": "my-bundle", "version": "1.0.0"}
]
// after
{
"schema_version": "1",
"bundles": [
{"bundle_id": "my-bundle", "version": "1.0.0"}
]
} Defensive patterns
Strategy: validation
Validate before calling
import json
from pathlib import Path
def records_is_object(path: Path) -> bool:
return isinstance(json.loads(path.read_text()), dict) Type guard
def is_records_object(data: object) -> bool:
return isinstance(data, dict) Try / catch
try:
records = load_records(project_root)
except BundlerError as e:
if "Corrupt records file" in str(e):
# back up the file, then either repair to {schema_version, bundles} or
# delete it and reinstall bundles to rebuild state
... Prevention
- The records file's top level is an object with schema_version and bundles keys.
- Avoid editors/formatters that might rewrite the whole document into an array.
- Restore .specify state from version control rather than editing by hand.
When it happens
Trigger: load_records(project_root) finds the records path exists, load_json returns a list/scalar, and the isinstance(data, dict) guard raises before schema-version checking.
Common situations: A records file overwritten with a JSON array of records (dropping the wrapper object); truncation/corruption after a crash; editing in a tool that reformatted the whole document.
Related errors
- Each installed-bundle record must be a mapping.
- Corrupt record: 'contributed_components' must be a list.
- Corrupt records file: an installed-bundle record is missing
- Corrupt records file: record for bundle '{bundle_id}' is mis
- Corrupt records file: {path} — missing 'schema_version'. Exp
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/0969d98c99cb8333.
Report an issue: GitHub.