affaan-m/ECC · error · ContractError

receipt reference has an invalid finite source duration

Error message

receipt reference has an invalid finite source duration

What it means

Receipt "references" entries must include a "source_duration" that is a finite real number (int or float, not NaN/inf, not bool). If _is_finite_real rejects the value, ContractError('receipt reference has an invalid finite source duration') is raised. The duration anchors probe-evidence validation performed immediately after.

Solutions

  1. Add a numeric (int/float) "source_duration" > 0 to every entry under "references"
  2. Convert string durations with float(value) before building the receipt
  3. Fix the JSON emitter to use allow_nan=False and emit real numbers
  4. If the entry is evidence rather than a reference, move it to "evidence_files" where duration is not required

Example fix

// before
{"path": "ref.csv", "sha256": "..", "source_duration": "12.5"}
// after
{"path": "ref.csv", "sha256": "..", "source_duration": 12.5}
Defensive patterns

Strategy: validation

Validate before calling

import math

def duration_ok(entry):
    d = entry.get('source_duration')
    return isinstance(d, (int, float)) and not isinstance(d, bool) and math.isfinite(d)

Type guard

def is_finite_real(v) -> bool:
    return isinstance(v, (int, float)) and not isinstance(v, bool) and math.isfinite(v)

Try / catch

try:
    validate_artifact_receipt(receipt, out_dir)
except ContractError as e:
    if 'invalid finite source duration' in str(e):
        for s in receipt['references']:
            s['source_duration'] = float(s['source_duration'])
    raise

Prevention

When it happens

Trigger: A reference entry whose "source_duration" is missing, null, a string like "3.5", a bool, NaN, or +/-Infinity.

Common situations: Duration serialized as a string by a custom serializer; JSON produced with NaN/Infinity via non-strict dumps; references copied from "evidence_files" entries which do not carry durations; hand-written receipts omitting the field.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

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

    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:
            metadata = path.lstat()
        except FileNotFoundError:
            if source_policy == "require_available":
                raise ContractError(f"receipt source is unavailable: {source_path}") from None
            continue

View on GitHub (pinned to 8321021c54)