affaan-m/ECC · error · ContractError
receipt contains an invalid source
Error message
receipt {key} contains an invalid source What it means
Every entry inside a receipt's "references" or "evidence_files" list must be an object (dict) describing one source file. If any element is a scalar, string, list, or null, validate_artifact_receipt raises ContractError('receipt {key} contains an invalid source'). The check guarantees the validator can safely read each entry's "path" and "sha256" keys.
Solutions
- Replace each list element with an object of the form {"path": <str>, "sha256": <64-hex str>}, optionally with "source_duration" and "probe" for references
- Remove null or placeholder entries from the list
- Regenerate the receipt via tasteforge so entries are emitted in the correct shape
Example fix
// before
"evidence_files": ["evidence/notes.txt"]
// after
"evidence_files": [{"path": "evidence/notes.txt", "sha256": "<64 hex chars>"}] Defensive patterns
Strategy: type-guard
Validate before calling
def sources_ok(receipt, key):
return all(isinstance(s, dict) for s in receipt.get(key, [])) Type guard
def is_source(entry) -> bool:
return isinstance(entry, dict) and isinstance(entry.get('path'), str)
receipt[key] = [s for s in raw if is_source(s)] Try / catch
try:
validate_artifact_receipt(receipt, out_dir)
except ContractError as e:
if 'contains an invalid source' in str(e):
receipt[key] = [s for s in receipt[key] if isinstance(s, dict)]
raise Prevention
- Represent each source as an object with path/sha256 keys, never a bare string
- Filter or reject non-dict entries at receipt-build time
- Add a unit test asserting every source entry is a dict
When it happens
Trigger: A receipt whose references/evidence_files list contains non-object elements — e.g. bare path strings like ["src/data.csv"], nested lists, numbers, or a null entry accidentally left in the array.
Common situations: Receipts authored by hand where sources were written as path strings instead of descriptor objects; generators that appended raw paths; template errors leaving placeholder null entries; JSON produced by joining strings with commas then splitting.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
Related errors
- artifact path must be a non-empty relative path
- receipt contains duplicate artifact paths
- receipt must be a list
- Unsupported asset receipt schema
- -32602
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/49ceb658a4c57b5f.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/contract.py:323
def validate_artifact_receipt(out_dir: str | Path, receipt: dict[str, Any]) -> None:
"""Verify that the receipt binds every emitted artifact and its provenance."""
out_dir = Path(out_dir).resolve()
entries = receipt.get("evidence_artifacts")
if not isinstance(entries, list):
raise ContractError("receipt evidence_artifacts must be a list")
if not all(isinstance(entry, dict) for entry in entries):
raise ContractError("receipt evidence_artifacts entries must be objects")
known_sources: set[tuple[str, str]] = set()
source_durations: dict[tuple[str, str], float] = {}
for key in ("references", "evidence_files"):
sources = receipt.get(key, [])
if not isinstance(sources, list):
raise ContractError(f"receipt {key} must be a list")
for source in sources:
if not isinstance(source, dict):
raise ContractError(f"receipt {key} contains an invalid source")
source_path = source.get("path")
expected_digest = source.get("sha256")
if (not isinstance(source_path, str) or not source_path
or not isinstance(expected_digest, str)
or not re.fullmatch(r"[0-9a-f]{64}", expected_digest)):
raise ContractError("receipt has an invalid source identity")
known_sources.add((source_path, expected_digest))
if key == "references":
source_duration = source.get("source_duration")
if not _is_finite_real(source_duration):
raise ContractError("receipt reference has an invalid finite source duration")
source_duration = cast(float, source_duration)
if float(source_duration) <= 0:
raise ContractError("receipt reference has an invalid finite source duration")
source_durations[(source_path, expected_digest)] = float(source_duration)
_validate_probe_evidence(
source.get("probe"), float(source_duration), label="receipt reference"
)View on GitHub (pinned to 8321021c54)