github/spec-kit · error · ValueError
Integration manifest 'files' at {path} must be a mapping of
Error message
Integration manifest 'files' at {path} must be a mapping of string paths to string hashes What it means
IntegrationManifest.load() found the 'files' entry is missing-wrong-type or its items are not string->string pairs. The files map is path (string) to SHA-256 hash (string); any non-string key or value — including a nested object or numeric hash — is rejected.
Source
Thrown at src/specify_cli/integrations/manifest.py:492
raise ValueError(
f"Integration manifest at {path} is not valid UTF-8"
) from exc
except json.JSONDecodeError as exc:
raise ValueError(
f"Integration manifest at {path} contains invalid JSON"
) from exc
if not isinstance(data, dict):
raise ValueError(
f"Integration manifest at {path} must be a JSON object, "
f"got {type(data).__name__}"
)
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 trackedView on GitHub (pinned to bf88c9f9a8)
Solutions
- python -m json.tool the file and check every files entry is "<posix rel path>": "<64-hex sha256>"
- Restore from git or delete + re-run specify integration install <key>
- Do not hand-edit hashes; use record_file/record_existing via the CLI instead
Example fix
# before
"files": {"a.md": 12345678}
# after
"files": {"a.md": "1234567890abcdef..."} Defensive patterns
Strategy: validation
Validate before calling
files = data.get("files", {})
ok = isinstance(files, dict) and all(
isinstance(k, str) and isinstance(v, str) for k, v in files.items()
)
if not ok:
regenerate_manifest(key, root) Type guard
def is_valid_files_map(files: object) -> bool:
return isinstance(files, dict) and all(
isinstance(k, str) and isinstance(v, str) for k, v in files.items()
) Try / catch
try:
IntegrationManifest.load(key, root)
except ValueError as exc:
if "must be a mapping of string paths" in str(exc):
regenerate_manifest(key, root)
else:
raise Prevention
- Do not hand-edit hashes; use the CLI to re-record files
- Keep hashes as 64-char hex strings
- Validate the shape after any scripted transformation
When it happens
Trigger: A manifest where "files" is a list, null, or a dict containing e.g. a list of hashes, an int hash, or a nested mapping per file; typically from hand edits or a schema drift between CLI versions/tools.
Common situations: Users changing a hash value to null to 'untrack' a file; third-party tools rewriting hashes as numbers; older/custom generators emitting a different shape.
Related errors
- Integration manifest 'recovered_files' at {path} must be a l
- {source} contains an invalid bundle manifest:\n - " + "\n
- Integration manifest at {path} must be a JSON object, got {t
- Aliases for command {cmd_name!r} must be a list
- auth.json must be a JSON object, got {type(raw).__name__}
AI-assisted analysis of github/spec-kit@bf88c9f9a8 (2026-08-14).
Data as JSON: /api/errors/98f1be92df050cee.
Report an issue: GitHub.