affaan-m/ECC · error · ValueError

no clips to write - a timeline needs at least one event

Error message

no clips to write - a timeline needs at least one event

What it means

timeline.py raises ValueError('no clips to write - a timeline needs at least one event') in _normalise when the resulting normalized clip list is empty, i.e. the caller passed an empty clips list. A timeline with zero events cannot produce valid FCPXML/EDL.

Solutions

  1. Pass at least one valid clip dict with path and positive duration.
  2. Check why the clips list is empty — log/inspect it before calling.
  3. Guard at the call site: `if not clips: skip / raise earlier with context`.
  4. Fix the upstream collection/filtering that produced an empty list.

Example fix

// before
build_fcpxml([])  # ValueError
// after
if not clips:
    raise ValueError('no clips selected; nothing to build')
build_fcpxml(clips, fps=30)
Defensive patterns

Strategy: validation

Validate before calling

def require_non_empty(clips):
    if not clips:
        raise ValueError('no clips to write - a timeline needs at least one event')
    return clips

Type guard

def has_clips(clips) -> bool:
    return isinstance(clips, list) and len(clips) > 0

Try / catch

try:
    write_timeline(clips, out_path, fmt='fcpxml')
except ValueError as e:
    if 'no clips to write' in str(e):
        logger.warning('nothing to build; skipping timeline output')
        return None

Prevention

When it happens

Trigger: Calling build_fcpxml or build_edl (or write_timeline) with clips=[] or None-ish empty input.

Common situations: Upstream filter step removed all clips; file list was empty because the directory had no media; conditional logic skipped adding clips silently.

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/6411d7df6367f3bd. Report an issue: GitHub.

Appendix: source

Thrown at skills/taste-application/scripts/taste/timeline.py:235

        if not path:
            raise ValueError(f"clip {i} has no 'path'")
        dur = float(c.get("duration") or 0.0)
        if dur <= 0:
            raise ValueError(f"clip {i} ({path}) has non-positive duration {dur!r}")
        frames = max(1, seconds_to_frames(dur, fps))  # never emit a zero-length event
        name = str(c.get("name") or Path(path).stem)
        out.append(
            {
                "path": path,
                "name": name,
                "frames": frames,
                "offset_frames": offset,
                "seconds": dur,
            }
        )
        offset += frames
    if not out:
        raise ValueError("no clips to write - a timeline needs at least one event")
    return out


def _file_uri(path: str) -> str:
    """Absolute ``file://`` URI. Works for paths that do not exist yet."""
    p = Path(path)
    if not p.is_absolute():
        p = Path.cwd() / p
    # as_uri() percent-escapes correctly; normalise away '..' without resolving
    # symlinks or requiring the file to exist.
    return Path(str(p)).absolute().as_uri()


def _format_name(width: int, height: int, fps: float | Fraction) -> str:
    f = fps_fraction(fps)
    rate = float(f)
    label = f"{rate:.2f}".rstrip("0").rstrip(".").replace(".", "")
    return f"FFVideoFormat{height}p{label}"

View on GitHub (pinned to 8321021c54)