affaan-m/ECC · error · ContractError

effect lacks reference evidence

Error message

effect {event.get('effect')} lacks reference evidence

What it means

Every effect event must carry reference evidence: a dict under the 'evidence' key that anchors the effect to source media. If 'evidence' is missing or is not a dict, the event's effect name is interpolated into the error to identify the offender. Evidence is required so effect outputs can be verified against the source material.

Solutions

  1. Attach a valid evidence dict to the event: event['evidence'] = {'time': ..., 'source_duration': ..., 'reference_sha256': ...}.
  2. Check the recipe generator/reference-lookup step for why evidence was not attached.
  3. Fix key typos so the evidence dict lands under 'evidence'.

Example fix

# before
event = {"effect": "cv_blur", "time": 1.0, "duration": 2.0}
# after
event = {"effect": "cv_blur", "time": 1.0, "duration": 2.0,
         "evidence": {"time": 1.0, "source_duration": 10.0, "reference_sha256": "<hex>"}}
Defensive patterns

Strategy: validation

Validate before calling

for ev in recipe["events"]:
    if not isinstance(ev.get("evidence"), dict):
        raise ValueError(f"event {ev.get('effect')} is missing an evidence dict")

Type guard

def has_evidence(ev: dict) -> bool:
    return isinstance(ev.get("evidence"), dict)

Try / catch

try:
    validate_effect_recipe(recipe)
except ContractError as exc:
    if "lacks reference evidence" in str(exc):
        effect = extract_effect_name(str(exc))
        recipe = {**recipe, "events": [attach_evidence(ev, effect) if not isinstance(ev.get("evidence"), dict) else ev for ev in recipe["events"]]}
        validate_effect_recipe(recipe)
    else:
        raise

Prevention

When it happens

Trigger: validate_effect_recipe called where an event dict has no 'evidence' key, or evidence is None, a list, or any non-dict value.

Common situations: Hand-built events that skip the evidence block; a generator failing to attach evidence when reference media lookup fails; JSON schemas from older versions without evidence; typos like 'evidences' or 'ref'.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


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

Appendix: source

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

    timeline = recipe.get("timeline_duration")
    if not _is_finite_real(timeline):
        raise ContractError("effect recipe must declare a finite positive timeline duration")
    timeline = cast(float, timeline)
    if float(timeline) <= 0:
        raise ContractError("effect recipe must declare a finite positive timeline duration")
    for event in events:
        start = event.get("time")
        duration = event.get("duration")
        if (not _is_finite_real(start) or not _is_finite_real(duration)
                or float(start) < 0 or float(duration) <= 0):
            raise ContractError("effect event start and duration must be finite positive timeline values")
        start = cast(float, start)
        duration = cast(float, duration)
        if float(start) + float(duration) > float(timeline) + 1e-9:
            raise ContractError("effect event end exceeds the declared timeline")
        evidence = event.get("evidence")
        if not isinstance(evidence, dict):
            raise ContractError(f"effect {event.get('effect')} lacks reference evidence")
        _validate_media_time(
            evidence.get("time"), evidence.get("source_duration"), label="effect evidence time"
        )
        if reference_durations is not None:
            digest = evidence.get("reference_sha256")
            expected_duration = reference_durations.get(digest) if isinstance(digest, str) else None
            if expected_duration is None or evidence.get("source_duration") != expected_duration:
                raise ContractError("effect evidence source duration is not bound to its receipt reference")
    times = [float(event["time"]) for event in events]
    if times != sorted(times) or len(times) != len(set(times)):
        raise ContractError("effect event times must be unique and increasing")
    intervals = [round(b - a, 6) for a, b in zip(times, times[1:])]  # noqa: RUF007
    if len(set(intervals)) <= 1:
        raise ContractError("stochastic schedule is periodic; intervals must vary")
    for period in range(1, len(intervals) // 2 + 1):
        if all(intervals[index] == intervals[index % period] for index in range(len(intervals))):
            raise ContractError("stochastic schedule is periodic; repeating interval cycle")
    if recipe.get("periodic") is not False:

View on GitHub (pinned to 8321021c54)