affaan-m/ECC · error · FalError
merge_videos() needs at least one video URL
Error message
merge_videos() needs at least one video URL
What it means
merge_videos concatenates a list of hosted video URLs via the fal.ai compose/merge endpoint. Because concatenating nothing is meaningless, the library raises FalError up front when the list is empty, before any network request is made.
Solutions
- Pass a non-empty list of video URLs to merge_videos
- Check that the list is populated before calling (assert video_urls)
- Trace why the upstream generation steps returned no URLs if the list should have content
Example fix
# before merge_videos(clips) # after assert clips, 'no clips to merge' merged = merge_videos(clips)
Defensive patterns
Strategy: validation
Validate before calling
if not video_urls:
raise ValueError('merge_videos requires at least one URL') Type guard
def has_videos(video_urls) -> bool:
return bool(video_urls) Prevention
- Check the clips list is non-empty before merging
- Propagate errors from earlier clip-generation steps rather than filtering silently
- Assert len(video_urls) > 0 at the top of merge pipelines
- Keep generated URLs in a list you can inspect before the merge step
When it happens
Trigger: merge_videos([]) or merge_videos(videos) where videos is an empty list — typically because earlier generation steps produced nothing or were filtered out.
Common situations: Pipeline stage collected video URLs into a list that ended up empty after filtering failed generations; forgetting to pass clip URLs generated in a previous step; variable shadowing or a failed upload leaving the list empty.
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
- image_to_3d needs at least one image
- nothing to concatenate
- analyze() needs at least one frame
- analyze() needs at least one frame
- at least one explicit seed is required
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/2da7966335d15b5c.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/taste/falapi.py:647
result = submit(ENDPOINTS["extract_frame"], payload, timeout)
return first_url(result, ENDPOINTS["extract_frame"])
def compose(tracks: list[dict], *, timeout: int = 900) -> str:
"""Composite timeline tracks into one video. Returns the output URL.
``tracks`` is passed straight through so the caller owns the timeline
shape; the ffmpeg-api track schema is another default worth verifying
before a live run.
"""
result = submit(ENDPOINTS["compose"], {"tracks": tracks}, timeout)
return first_url(result, ENDPOINTS["compose"])
def merge_videos(video_urls: list[str], *, timeout: int = 900) -> str:
"""Concatenate videos end to end. Returns the merged URL."""
if not video_urls:
raise FalError("merge_videos() needs at least one video URL")
payload = {"video_urls": list(video_urls)}
result = submit(ENDPOINTS["merge_videos"], payload, timeout)
return first_url(result, ENDPOINTS["merge_videos"])
# ---------------------------------------------------------------------------
# download
# ---------------------------------------------------------------------------
MAX_DOWNLOAD_BYTES = 2 * 1024 * 1024 * 1024 # bounded large video/GLB downloads
def _validate_download_url(url: str) -> None:
try:
parsed = urllib.parse.urlsplit(url)
host = parsed.hostname or ""
valid = (parsed.scheme == "https" and not parsed.usernameView on GitHub (pinned to 8321021c54)