github/spec-kit · error · ValueError

Integration manifest 'recovered_files' at {path} must be a l

Error message

Integration manifest 'recovered_files' at {path} must be a list of string paths

What it means

IntegrationManifest.load() validates the optional 'recovered_files' array: it must be a list of strings. It tracks files re-adopted after recovery, so non-string entries (ints, objects, nulls) indicate corruption or schema misuse.

Source

Thrown at src/specify_cli/integrations/manifest.py:505

        files = data.get("files", {})
        if not isinstance(files, dict) or not all(
            isinstance(k, str) and isinstance(v, str) for k, v in files.items()
        ):
            raise ValueError(
                f"Integration manifest 'files' at {path} must be a "
                "mapping of string paths to string hashes"
            )

        inst.version = data.get("version", "")
        inst._installed_at = data.get("installed_at", "")
        inst._files = files

        recovered = data.get("recovered_files", [])
        if not isinstance(recovered, list) or not all(
            isinstance(p, str) for p in recovered
        ):
            raise ValueError(
                f"Integration manifest 'recovered_files' at {path} must be a "
                "list of string paths"
            )
        inst._recovered_files = set(recovered)
        # Drop any recovered_files entries that don't correspond to tracked
        # files — defensive against externally-edited or partially-corrupted
        # manifests. Inconsistent state self-corrects on next save().
        inst._recovered_files &= set(inst._files.keys())

        stored_key = data.get("integration", "")
        if stored_key and stored_key != key:
            raise ValueError(
                f"Manifest at {path} belongs to integration {stored_key!r}, "
                f"not {key!r}"
            )

        return inst

View on GitHub (pinned to bf88c9f9a8)

Solutions

  1. Check that recovered_files is [] or a list of path strings matching tracked files
  2. Safest fix: delete the manifest and re-run specify integration install <key> (load() also self-heals stray entries on next save, but the type error must be fixed first)
  3. Restore a known-good copy from git

Example fix

# before
"recovered_files": {"a.md": true}
# after
"recovered_files": ["a.md"]
Defensive patterns

Strategy: validation

Validate before calling

recovered = data.get("recovered_files", [])
ok = isinstance(recovered, list) and all(isinstance(p, str) for p in recovered)
if not ok:
    data["recovered_files"] = []  # field is optional; reset it
    rewrite_manifest(data)

Type guard

def is_valid_recovered_list(v: object) -> bool:
    return isinstance(v, list) and all(isinstance(p, str) for p in v)

Try / catch

try:
    IntegrationManifest.load(key, root)
except ValueError as exc:
    if "recovered_files" in str(exc):
        reset_recovered_field_and_reload()
    else:
        raise

Prevention

When it happens

Trigger: A manifest where recovered_files is a dict, a string, or a list containing non-strings — from manual edits, jq scripts, or a different tool version writing an incompatible shape.

Common situations: Hand-merging two manifests; scripts copying recovered_files between files; partial JSON edits.

Related errors


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