affaan-m/ECC · error · ContractError

effect event start and duration must be finite positive…

Error message

effect event start and duration must be finite positive timeline values

What it means

Each event in the schedule must have a 'time' (>= 0) and a 'duration' (> 0) that are both finite real numbers. Missing keys, strings, bools, NaN/inf, negative starts, or zero/negative durations all raise this error.

Solutions

  1. Ensure every event has numeric time >= 0 and duration > 0 (floats or ints).
  2. Convert string/None values to floats before validation and reject non-numeric ones.
  3. Clamp or reject negative starts and zero durations at recipe-generation time.

Example fix

# before
event = {"time": "0.5", "duration": 0}
# after
event = {"time": 0.5, "duration": 2.0}
Defensive patterns

Strategy: validation

Validate before calling

for ev in recipe["events"]:
    t, d = ev.get("time"), ev.get("duration")
    ok = (isinstance(t, (int, float)) and not isinstance(t, bool) and math.isfinite(t) and t >= 0
        and isinstance(d, (int, float)) and not isinstance(d, bool) and math.isfinite(d) and d > 0)
    if not ok:
        raise ValueError(f"event has invalid time/duration: {t!r}, {d!r}")

Type guard

def event_time_valid(ev: dict) -> bool:
    t, d = ev.get("time"), ev.get("duration")
    return (isinstance(t, (int, float)) and not isinstance(t, bool)
        and math.isfinite(t) and t >= 0
        and isinstance(d, (int, float)) and not isinstance(d, bool)
        and math.isfinite(d) and d > 0)

Try / catch

try:
    validate_effect_recipe(recipe)
except ContractError as exc:
    if "finite positive timeline values" in str(exc):
        recipe = {**recipe, "events": [normalize_event_times(ev) for ev in recipe["events"]]}
        validate_effect_recipe(recipe)
    else:
        raise

Prevention

When it happens

Trigger: validate_effect_recipe called where any event dict lacks 'time' or 'duration', stores them as strings (e.g. from JSON/config), uses NaN/inf, has time < 0, or duration <= 0.

Common situations: Durations parsed from YAML/JSON kept as strings like '2.5'; a default duration of 0; negative start times from clip-relative offsets; None filling missing optional fields.

Understand the failure class

Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.

Related errors


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

Appendix: source

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

    if not isinstance(recipe.get("seed"), int) or isinstance(recipe.get("seed"), bool):
        raise ContractError("effect recipe must have an integer seed")
    if recipe.get("rng_algorithm") != "python.random.Random/v1":
        raise ContractError("effect recipe must declare its seeded RNG algorithm")
    events = recipe.get("events")
    if not isinstance(events, list) or len(events) < 3:
        raise ContractError("effect recipe needs at least three scheduled events")
    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")

View on GitHub (pinned to 8321021c54)