affaan-m/ECC · error · ContractError

receipt has an invalid source identity

Error message

receipt has an invalid source identity

What it means

Each receipt source descriptor must carry a non-empty string "path" and a "sha256" value that is a string of exactly 64 lowercase hexadecimal characters. If either is missing, empty, or malformed, validate_artifact_receipt raises ContractError('receipt has an invalid source identity'). This identity (path, digest) is later used to locate and verify the source file on disk.

Solutions

  1. Set "path" to a non-empty relative path string and "sha256" to the full 64-char lowercase hex digest of the file
  2. Recompute the digest with `sha256sum <file>` (or hashlib.sha256(...).hexdigest()) and paste it verbatim
  3. Lowercase/strip any prefix from an existing digest
  4. Regenerate the receipt with tasteforge so identities are computed correctly

Example fix

// before
{"path": "", "sha256": "A3F..."}   // empty path, uppercase
// after
{"path": "src/data.csv", "sha256": "a3f..."}  // full 64-char lowercase hex
Defensive patterns

Strategy: validation

Validate before calling

import re
DIGEST = re.compile(r"[0-9a-f]{64}")

def identity_ok(entry):
    return bool(entry.get('path')) and isinstance(entry.get('path'), str) \
        and isinstance(entry.get('sha256'), str) and bool(DIGEST.fullmatch(entry['sha256']))

Type guard

def has_valid_identity(entry) -> bool:
    p, d = entry.get('path'), entry.get('sha256')
    return isinstance(p, str) and bool(p) and isinstance(d, str) \
        and re.fullmatch(r"[0-9a-f]{64}", d) is not None

Try / catch

try:
    validate_artifact_receipt(receipt, out_dir)
except ContractError as e:
    if 'invalid source identity' in str(e):
        for s in receipt['references'] + receipt['evidence_files']:
            s['sha256'] = hashlib.sha256(Path(s['path']).read_bytes()).hexdigest()
    raise

Prevention

When it happens

Trigger: A source entry with a missing/empty "path", a non-string or empty "sha256", an uppercase hex digest, a truncated digest (e.g. a 12-char short hash), or a digest prefixed with "sha256:".

Common situations: Digests computed with tools that output uppercase or prefixed hashes (sha256sum output is fine, but 'SHA256: ...' is not); receipts generated before the digest field was added; paths left blank by templating; using a git short SHA instead of the full sha256.

Understand the failure class

Background: "invalid id" errors: invalid identifier format — why libraries reject IDs before lookup, and how to fix them — this error's family across 37 libraries.

Related errors


AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16). Data as JSON: /api/errors/7b1e0df3dc597916. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/contract.py:329

    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"
                )
    source_policy = receipt.get("source_availability_policy")
    if known_sources and source_policy not in {"allow_unavailable", "require_available"}:
        raise ContractError("receipt must declare an explicit source availability policy")
    for source_path, expected_digest in sorted(known_sources):
        path = Path(source_path)
        try:

View on GitHub (pinned to 8321021c54)