affaan-m/ECC · error · ValueError

nothing to concatenate

Error message

nothing to concatenate

What it means

concat() raises this ValueError when given an empty clips list. The function joins a list of clip paths into one file via ffmpeg's concat demuxer, which requires at least one entry in the generated listing file; an empty list would produce a useless/invalid concat manifest.

Solutions

  1. Ensure at least one clip path is passed; validate the list length before calling concat()
  2. Check the upstream step (cut_take) actually produced output files in dest_dir
  3. Fix the glob/filter that produced the empty list
  4. If an empty result is legitimate, handle it before calling concat rather than relying on this error

Example fix

// before
concat(clips, out)  # clips may be []
// after
if not clips:
    raise RuntimeError("upstream cut produced no clips")
concat(clips, out)
Defensive patterns

Strategy: validation

Validate before calling

clips = [c for c in clips if Path(c).is_file()]
if not clips:
    raise RuntimeError("no valid clips to concatenate")

Type guard

def has_clips(clips) -> bool:
    from pathlib import Path
    return bool(clips) and all(Path(c).is_file() for c in clips)

Try / catch

try:
    concat(clips, dst)
except ValueError as e:
    if str(e) == "nothing to concatenate":
        print("upstream pipeline produced no clips")
    raise

Prevention

When it happens

Trigger: Calling concat([], dst) — i.e. no clip paths supplied, typically when an upstream step (e.g. cut_take) produced zero output files and the result was passed through unchecked.

Common situations: A shot-cutting pass matched no segments so the clip list came back empty; a glob pattern matched nothing; filtering clips by a criteria that excluded everything before calling concat.

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


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

Appendix: source

Thrown at skills/taste-application/scripts/taste/assemble.py:181

        f"[0:v]format=gbrp[base];"
        f"[base][ov]blend=all_mode={blend or 'screen'}:shortest=1,format=yuv420p"
    )
    _run([
        "ffmpeg", "-nostdin", "-loglevel", "error", "-y",
        # Keep the still alive until the video ends; shortest=1 otherwise
        # terminates every shot after the image's single decoded frame.
        "-i", str(clip), "-loop", "1", "-i", str(image), "-filter_complex", fc,
        "-c:v", "libx264", "-crf", "14", "-preset", "veryfast",
        "-pix_fmt", "yuv420p", "-an", str(dst),
    ])
    return Path(dst)


def concat(clips: list[str | Path], dst: str | Path, fps: float = 24.0) -> Path:
    """Join clips into one file. Assumes they already share codec and size."""
    clips = [Path(c) for c in clips]
    if not clips:
        raise ValueError("nothing to concatenate")
    dst = Path(dst)
    dst.parent.mkdir(parents=True, exist_ok=True)
    listing = dst.parent / f"{dst.stem}_concat.txt"
    listing.write_text("".join(f"file '{c.resolve().as_posix()}'\n" for c in clips))
    _run([
        "ffmpeg", "-nostdin", "-loglevel", "error", "-y",
        "-f", "concat", "-safe", "0", "-i", str(listing),
        "-vf", f"fps={fps:.6f}",
        "-c:v", "libx264", "-crf", "16", "-pix_fmt", "yuv420p", str(dst),
    ])
    listing.unlink(missing_ok=True)
    return dst


def normalize(
    src: str | Path,
    dst: str | Path,
    width: int,

View on GitHub (pinned to 8321021c54)