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
- Attach a valid evidence dict to the event: event['evidence'] = {'time': ..., 'source_duration': ..., 'reference_sha256': ...}.
- Check the recipe generator/reference-lookup step for why evidence was not attached.
- 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
- Require evidence at event-construction time (fail fast in your builder).
- Verify the reference-media lookup succeeds before emitting events.
- Spell the key exactly 'evidence'; avoid aliases.
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
- effect event end exceeds the declared timeline
- effect event start and duration must be finite positive…
- effect evidence source duration is not bound to its receipt…
- effect recipe needs at least three scheduled events
- exactly one candidate-keyed health assertion is required
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)