affaan-m/ECC · error · ValueError
native clip snapshot required
Error message
native clip snapshot required
What it means
_snapshot requires snapshot.timeline_readback to be a non-empty dict mapping track names to clip lists; this is the native clip evidence the whole preservation workflow binds against. Missing, empty, or wrong-typed readback means there is no original clip data to preserve, so the library refuses to build a bundle.
Solutions
- Re-export the snapshot from a timeline that actually contains clips so timeline_readback is populated.
- Add the timeline_readback object with keys like "video1", "audio1" mapping to clip lists.
- Check the export wasn't truncated — validate the JSON is complete and non-empty.
- Verify you're pointing at the snapshot for the intended timeline, not an empty placeholder.
Example fix
// before
{"project": "P", "timeline": "T", "timeline_readback": {}}
// after
{"project": "P", "timeline": "T", "timeline_readback": {"video1": [{"path": "...", "name": "clip", "start": 0, "end": 100, "left_offset": 0, "right_offset": 0, "enabled": true, "properties": {}}], "audio1": [...]}} Defensive patterns
Strategy: validation
Validate before calling
def has_readback(snapshot):
tracks = snapshot.get("timeline_readback") if isinstance(snapshot, dict) else None
return isinstance(tracks, dict) and len(tracks) > 0 and all(isinstance(v, list) for v in tracks.values()) Type guard
def has_timeline_readback(snapshot) -> bool:
t = snapshot.get("timeline_readback") if isinstance(snapshot, dict) else None
return isinstance(t, dict) and bool(t) Try / catch
try:
bundle = build_application_bundle(config, None, local_only=True)
except ValueError as exc:
if "native clip snapshot required" in str(exc):
print("timeline_readback missing/empty — re-export from a timeline with clips")
raise Prevention
- Verify the timeline has clips before exporting a snapshot.
- Validate snapshot completeness (readback present and non-empty) at export time.
- Confirm file integrity after export (non-truncated, expected keys).
- Never point at placeholder or template snapshots.
When it happens
Trigger: build_application_bundle where the snapshot has no timeline_readback key, it is null, an empty object {}, or a list/string instead of a dict of track->clips.
Common situations: An empty or blank timeline exported; a snapshot from a tool that doesn't emit readback; a hand-built snapshot omitting the readback section; a truncated export that dropped the last field.
Understand the failure class
Background: "must not be empty", "cannot be empty" — required-field validation errors across open-source libraries — this error's family across 41 libraries.
Related errors
- at least one genre spec is required
- invalid native snapshot track
- memory body must contain non-whitespace context.
- native clip state is incomplete
- native fps missing
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/f40b2d8078fedac3.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/integration.py:216
# Resolve's conventional decimal NTSC labels represent these exact rates.
ntsc = {"23.976": "24000/1001", "29.97": "30000/1001", "59.94": "60000/1001"}
try:
if type(native_fps) not in (str, int, float):
raise ValueError("native fps missing")
label = str(native_fps)
if not re.fullmatch(r"[0-9]{1,9}(?:\.[0-9]{1,12}|/[1-9][0-9]{0,8})?", label):
raise ValueError("native fps must use a bounded decimal or rational label")
native_rate = Fraction(ntsc.get(label, label))
if native_rate != Fraction(*_rate(baseline["fps"])):
raise ValueError("native fps differs")
except (ValueError, ZeroDivisionError) as exc:
raise ValueError("native snapshot fps is missing, invalid or contradictory") from exc
for cfg, key in [("project_name", "project"), ("timeline_name", "timeline")]:
if _text(baseline[cfg]) != snapshot.get(key):
raise ValueError("native snapshot identity mismatch")
tracks = snapshot.get("timeline_readback")
if not isinstance(tracks, dict) or not tracks:
raise ValueError("native clip snapshot required")
for track, clips in tracks.items():
if not re.fullmatch(r"(?:video|audio)[1-9][0-9]*", track) or not isinstance(clips, list):
raise ValueError("invalid native snapshot track")
for clip in clips:
_check_clip(clip, bounds)
return tracks
def _check_clip(clip: Any, bounds: list[int]) -> None:
required = {"path", "name", "start", "end", "left_offset", "right_offset", "enabled", "properties"}
if not isinstance(clip, dict) or not required <= clip.keys():
raise ValueError("native snapshot clip is incomplete")
_range([clip["start"], clip["end"]], bounds)
_integer(clip["left_offset"])
_integer(clip["right_offset"])
if clip["path"] is not None:
_text(clip["path"])
_text(clip["name"])View on GitHub (pinned to 8321021c54)