affaan-m/ECC · error · ValueError

cadence.json has no measured shots to plan from

Error message

cadence.json has no measured shots to plan from

What it means

apply_local validates that the loaded cadence.json is a dict containing either a 'shots' list or a 'mean_shot' entry. If the file exists but has neither (wrong shape, empty object, or non-dict like a list), planning shot durations is impossible, so it raises ValueError. This guards against corrupted or hand-edited cadence files.

Solutions

  1. Regenerate cadence.json with the pack's measurement pipeline so it contains 'shots' (or at least 'mean_shot').
  2. Inspect the JSON: it must be an object with a non-empty 'shots' list or a 'mean_shot' key.
  3. Fix hand-edited cadence.json to match the expected schema.
  4. Rebuild the style pack from source media if the cadence data is unrecoverable.

Example fix

// before
cadence.json -> {}  // apply_local raises
cadence.json -> []  // apply_local raises

// after
cadence.json -> {"shots": [1.2, 0.8, 1.5], "fps": 24}
Defensive patterns

Strategy: validation

Validate before calling

cad = json.loads(sp.cadence_path.read_text())
assert isinstance(cad, dict) and (cad.get("shots") or "mean_shot" in cad), "cadence.json invalid"

Type guard

def is_valid_cadence(cad) -> bool:
    return isinstance(cad, dict) and bool(cad.get("shots") or "mean_shot" in cad)

Try / catch

try:
    report = apply_local(sp, media=clips)
except ValueError as e:
    if "no measured shots" in str(e):
        regenerate_cadence(sp)
        report = apply_local(sp, media=clips)
    else:
        raise

Prevention

When it happens

Trigger: Calling apply_local(sp, ...) where sp.read_json(sp.cadence_path) returns an empty dict {}, a non-dict (list/str), or a dict lacking both 'shots' and 'mean_shot' keys.

Common situations: Manually creating a placeholder cadence.json that is empty or has the wrong schema; a cadence build step that produced no shots (e.g. empty input video set) and wrote an empty JSON object; a schema change between library versions.

Understand the failure class

Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.

Related errors


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

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/apply.py:161

    With ``no_repeat=True``, normalized source paths are used at most once;
    insufficient sources or source durations fail instead of repeating clips.
    Strict plans fill the nearest whole-frame target and never exceed source
    capacity. Media duration metadata must describe the available source.

    Returns an application report validated against
    ``schema.APPLICATION_REPORT_SCHEMA``. The report structurally cannot
    claim a provider run: ``provider`` is enum-locked to ``"none"`` and
    ``dry_run`` to ``true``.
    """
    if not media:
        raise ValueError("apply_local needs at least one media clip")

    if not sp.cadence_path.exists():
        raise ValueError("pack has no measured cadence (cadence.json is missing)")
    cadence = sp.read_json(sp.cadence_path)
    if not isinstance(cadence, dict) or not (cadence.get("shots") or "mean_shot" in cadence):
        raise ValueError("cadence.json has no measured shots to plan from")
    seq_fps = _positive(fps if fps is not None else cadence.get("fps", _DEFAULT_FPS), "fps")
    validated_media = []
    for clip in media:
        if not isinstance(clip, dict) or not isinstance(clip.get("path"), (str, Path)):
            raise ValueError("media clips require a local source path")
        if not str(clip["path"]).strip():
            raise ValueError("media clips require a local source path")
        validated_media.append({**clip, "duration": _positive(clip.get("duration"), "media duration")})
    target = _positive(duration if duration is not None else sum(
        c["duration"] for c in validated_media
    ), "target duration")
    planned = plan_shots(cadence, target)
    assignments = _strict_assign(planned, validated_media, target, seq_fps) if no_repeat else [
        (validated_media[i % len(validated_media)], max(1, timeline.seconds_to_frames(d, seq_fps)))
        for i, d in enumerate(planned)
    ]

    shots: list[dict[str, Any]] = []

View on GitHub (pinned to 8321021c54)