affaan-m/ECC · error · ContractError
artifact SHA-256 does not match receipt
Error message
artifact {relative} SHA-256 does not match receipt What it means
tasteforge's validate_artifact_receipt verifies each emitted artifact against the receipt manifest. This error means the SHA-256 recorded in the receipt for an artifact does not match the actual bytes on disk, so the artifact was modified after the receipt was generated. The library treats this as proof of tampering or a stale receipt and refuses the bundle.
Solutions
- Regenerate the artifact and the receipt together using the tasteforge pipeline so the digest is recomputed from the final bytes
- Recompute the correct SHA-256 (hashlib.sha256 of the file bytes) and update the receipt entry only if you intentionally changed the artifact and provenance still holds
- Restore the artifact to its original bytes (e.g. from git) so it matches the receipt
- Run validate_bundle in a clean checkout to confirm which side (artifact or receipt) drifted
Example fix
import hashlib
# before: receipt entry stale after artifact was touched
receipt['artifacts']['cover.png']['sha256'] = 'abc123...'
# after: recompute digest from actual file bytes
receipt['artifacts']['cover.png']['sha256'] = hashlib.sha256(
Path('out/cover.png').read_bytes()
).hexdigest() Defensive patterns
Strategy: validation
Validate before calling
import hashlib, pathlib assert receipt_entry['sha256'] == hashlib.sha256(pathlib.Path(artifact_path).read_bytes()).hexdigest()
Type guard
def digest_matches(path, expected: str) -> bool:
return hashlib.sha256(pathlib.Path(path).read_bytes()).hexdigest() == expected Try / catch
try:
validate_artifact_receipt(out_dir)
except ContractError as e:
if 'SHA-256 does not match' in str(e):
regenerate_artifacts_and_receipt(out_dir)
else:
raise Prevention
- Never edit emitted artifacts after receipt generation
- Regenerate receipt and artifacts in the same pipeline run
- Verify digests in CI before accepting bundles
- Store artifacts in git and restore them rather than hand-copying files
When it happens
Trigger: Calling validate_artifact_receipt (directly or via validate_bundle) when receipt['artifacts'][name]['sha256'] differs from _sha256(path) — e.g. the artifact file was edited, reformatted, or re-saved after receipt creation, or the receipt was regenerated with different content while the old file remains.
Common situations: Hand-editing a generated image/audio artifact, running an editor or image optimizer that rewrites files post-build, copying artifacts between machines with byte-altering conversion, regenerating artifacts without refreshing the receipt, or editing a receipt entry by hand without recomputing the digest.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- application bundle differs from its bound evidence
- approved text hash does not match
- artifact SHA-256 mismatch
- candidate content address or canonical configuration is…
- harness health evidence integrity verification failed
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/ee8a02630d1e4cb5.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/contract.py:405
relative = entry.get("path")
assert isinstance(relative, str)
path = (out_dir / relative).resolve()
try:
path.relative_to(out_dir)
except ValueError as error:
raise ContractError(f"artifact path escapes output directory: {relative}") from error
if entry.get("provider_execution") is not False:
raise ContractError(f"artifact {relative} permits provider execution")
if not isinstance(entry.get("genre_numbers"), list):
raise ContractError(f"artifact {relative} lacks genre binding")
modalities = entry.get("modalities")
if (not isinstance(modalities, list)
or any(modality not in _REQUIRED_MODALITIES for modality in modalities)):
raise ContractError(f"artifact {relative} has invalid modality binding")
if entry.get("bytes") != path.stat().st_size:
raise ContractError(f"artifact {relative} byte size does not match receipt")
if entry.get("sha256") != _sha256(path):
raise ContractError(f"artifact {relative} SHA-256 does not match receipt")
provenance = entry.get("provenance")
if not isinstance(provenance, list) or not provenance:
raise ContractError(f"artifact {relative} lacks exact reference/time provenance")
for source in provenance:
if not isinstance(source.get("reference_path"), str) or not source["reference_path"]:
raise ContractError(f"artifact {relative} has invalid reference path")
digest = source.get("reference_sha256")
if not isinstance(digest, str) or len(digest) != 64:
raise ContractError(f"artifact {relative} has invalid reference SHA-256")
if (source["reference_path"], digest) not in known_sources:
raise ContractError(f"artifact {relative} cites an unknown provenance source")
times = source.get("reference_times")
basis = source.get("time_basis")
if not isinstance(times, list) or basis not in {"media_seconds", "whole_file"}:
raise ContractError(f"artifact {relative} has invalid reference/time provenance")
if basis == "media_seconds" and not times:
raise ContractError(f"artifact {relative} lacks media reference times")
if basis == "whole_file" and times:View on GitHub (pinned to 8321021c54)