affaan-m/ECC · error · ContractError
artifact byte size does not match receipt
Error message
artifact {relative} byte size does not match receipt What it means
The receipt records each artifact's byte size at generation time; validation compares the recorded 'bytes' field with the actual file size on disk (path.stat().st_size). This ContractError is raised when they differ, meaning the artifact content changed after the receipt was written.
Solutions
- Regenerate the bundle and receipt together so recorded sizes match the files.
- Restore the artifact files to their original bytes (git restore / re-download) matching the receipt.
- Verify sizes with find out_dir -type f -printf '%s %p\n' and compare against receipt 'bytes' to identify which files drifted.
Example fix
# before (file edited after generation) python contract.py validate ./bundle # byte size does not match receipt # after tasteforge generate ./bundle && python contract.py validate ./bundle
Defensive patterns
Strategy: try-catch
Validate before calling
for e in receipt['artifacts']:
p = out_dir / e['path']
if p.is_file() and p.stat().st_size != e.get('bytes'):
raise SystemExit(f'size drift: {e["path"]} — regenerate receipt') Type guard
def size_matches(out_dir: Path, entry: dict) -> bool:
p = out_dir / entry.get('path', '')
return p.is_file() and p.stat().st_size == entry.get('bytes') Try / catch
try:
validate_artifact_receipt(out_dir, entries)
except ContractError as e:
if 'byte size does not match' in str(e):
regenerate_bundle(out_dir) # artifacts drifted; rebuild receipt+outputs together
else:
raise Prevention
- Regenerate bundle and receipt in one atomic step after any output change.
- Transfer bundles as archives in binary mode to avoid size/line-ending changes.
- Exclude the output directory from editor autosave/optimizer pipelines.
- Commit artifacts and receipt together in version control.
When it happens
Trigger: Calling validate_artifact_receipt()/validate_bundle() after an artifact file was edited, re-encoded, re-saved by an editor/tool, truncated during transfer, or regenerated without updating the receipt.
Common situations: An image re-saved by an editor or optimizer pipeline post-generation; text-mode transfer (FTP/zip) altering line endings and size; partial/corrupted copy; regenerated outputs paired with an old receipt.
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
- Local ingestion must have zero provider calls
- receipt binds missing artifact
- unbound emitted artifact
- application bundle differs from its bound evidence
- approval evidence must bind exact source, candidate and…
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/9814ca69e1bb56a1.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/contract.py:403
for entry in entries:
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:View on GitHub (pinned to 8321021c54)