affaan-m/ECC · error · ContractError

receipt source is unavailable

Error message

receipt source is unavailable: {source_path}

What it means

With "source_availability_policy": "require_available", every declared receipt source must exist on disk at validation time. If Path(source_path).lstat() raises FileNotFoundError and the policy is require_available, ContractError('receipt source is unavailable: <path>') is raised. Under allow_unavailable, missing files are silently skipped instead.

Solutions

  1. Restore the missing source file at the declared path (git checkout / re-download / pull LFS objects)
  2. Run validation from the same working directory used at generation so relative paths resolve
  3. Switch the receipt to "allow_unavailable" only if missing sources are genuinely acceptable
  4. Regenerate the receipt if the source set changed

Example fix

# before (from wrong cwd)
cd /tmp && python -m tasteforge validate bundle.tzst
# after
cd /path/to/project && python -m tasteforge validate bundle.tzst
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

def sources_present(receipt, base='.'):
    paths = [s['path'] for s in receipt.get('references', []) + receipt.get('evidence_files', [])]
    missing = [p for p in paths if not (Path(base) / p).exists()]
    return missing  # empty list means OK

Try / catch

try:
    validate_artifact_receipt(receipt, out_dir)
except ContractError as e:
    if str(e).startswith('receipt source is unavailable'):
        missing = str(e).rsplit(': ', 1)[1]
        # restore file, fix cwd, or switch policy before retrying
    raise

Prevention

When it happens

Trigger: validate_artifact_receipt/validate_bundle run in a working directory where a declared source file was deleted, renamed, or never checked out; running validation from the wrong cwd so relative paths don't resolve; CI checkouts that exclude large evidence files (LFS not pulled).

Common situations: Running the validator from a different directory than generation; files cleaned by `git clean`; Git LFS/GitLab sparse checkout skipping evidence assets; sources outside the repo on a machine that lacks them; case-sensitive filesystems where the path casing differs.

Understand the failure class

Background: "File not found" and ENOENT errors: why libraries can't find a file that should exist — this error's family across 50 libraries.

Related errors


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

Appendix: source

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

                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:
            metadata = path.lstat()
        except FileNotFoundError:
            if source_policy == "require_available":
                raise ContractError(f"receipt source is unavailable: {source_path}") from None
            continue
        if stat.S_ISLNK(metadata.st_mode) or not stat.S_ISREG(metadata.st_mode):
            raise ContractError(f"receipt source is not a safe regular file: {source_path}")
        try:
            actual_digest = _sha256(path)
        except FileNotFoundError:
            if source_policy == "require_available":
                raise ContractError(f"receipt source is unavailable: {source_path}") from None
            continue
        except OSError:
            raise ContractError(f"receipt source cannot be securely read: {source_path}") from None
        if actual_digest != expected_digest:
            raise ContractError(f"receipt source SHA-256 changed after generation: {source_path}")

    emitted = {
        path.relative_to(out_dir).as_posix()
        for path in out_dir.rglob("*")
        if path.is_file() and path.name != "receipt.json"

View on GitHub (pinned to 8321021c54)