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

  1. Replace each list element with an object of the form {"path": <str>, "sha256": <64-hex str>}, optionally with "source_duration" and "probe" for references
  2. Remove null or placeholder entries from the list
  3. 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

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


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)