affaan-m/ECC · error · SystemExit
every shot failed; nothing to compose
Error message
every shot failed; nothing to compose
What it means
Aggregate failure guard in apply(): every shot generation in the worker pool failed, leaving no takes to compose into the rough cut. Individual shot errors were already logged; this fires only when the result set is empty.
Solutions
- Inspect the per-shot errors logged above this message (API auth, rate limit, or provider outage are typical)
- Fix credentials/network and re-run with a new --out
- Run with --dry-run first to validate the pipeline without spend
Defensive patterns
Strategy: try-catch
When it happens
Trigger: Thrown at skills/taste-application/scripts/apply.py:409 when the library encounters an invalid state.
Common situations: See trigger scenarios.
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/6bede9786c77836c.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/apply.py:409
raise SystemExit("--overlay not found: " + ", ".join(str(m) for m in missing))
for o in overlays:
overlay_urls.append(falapi.upload(Path(o)))
print(f" overlays : {len(overlay_urls)}")
# Uploads are cached by (path, mtime, size), so the workers racing on the
# same handful of stills still only pay for each upload once.
lock = threading.Lock()
workers = max(1, min(int(concurrency), len(shots)))
print(f" generating : {len(shots)} shot(s), {workers} worker(s) ...")
with ThreadPoolExecutor(max_workers=workers) as pool:
list(pool.map(lambda s: _generate(s, base_video_url, lock), shots))
ok = [s for s in shots if s.video_url]
failed = [s for s in shots if not s.video_url]
for s in failed:
print(f" !! shot {s.index} failed: {s.error}", file=sys.stderr)
if not ok:
raise SystemExit("every shot failed; nothing to compose")
# Close ranks over any failed shot so the cut has no black hole in it.
timeline_clock = 0.0
for s in ok:
s.timeline_start = timeline_clock
timeline_clock += s.duration
# Generate long, trim short. Video models quantize to whole seconds with a
# floor of a few, but the pack's cadence is often faster than that (a 1.1s
# shot is normal in a fast reference). So each shot is requested at the
# model's nearest legal length and then cut back to its cadence-derived
# duration on the timeline - which is the only way the rough cut actually
# inherits the reference's rhythm instead of a 3s-per-clip floor.
tracks = [
{
"id": "shots",
"type": "video",
"keyframes": [View on GitHub (pinned to 8321021c54)