affaan-m/ECC · error · ValueError

target overlay tracks must be empty

Error message

target overlay tracks must be empty

What it means

apply_placements requires every video track above base_track_count that already exists on the target to be empty, so appended overlays are the only items on those tracks. If any such overlay track already contains clips, it raises before mutating, preventing silent stacking of overlays on leftover content. This is a safety check for the 'versioned duplicate timeline' workflow.

Solutions

  1. Delete or move any clips on video tracks above base_track_count on the target before calling apply_placements.
  2. Create a fresh duplicate of the source timeline for each run so overlay tracks start empty.
  3. Check tracks yourself first with GetItemListInTrack('video', i) and abort/clean if non-empty.

Example fix

// before
apply_placements(target, pool, placements, ...)  # second run
// after
for i in range(base+1, target.GetTrackCount("video")+1):
    for item in target.GetItemListInTrack("video", i):
        item.DeleteClip()
apply_placements(target, pool, placements, ...)
Defensive patterns

Strategy: validation

Validate before calling

for track in range(base_track_count + 1, timeline.GetTrackCount("video") + 1):
    if timeline.GetItemListInTrack("video", track):
        raise RuntimeError(f"overlay track V{track} is not empty")

Type guard

def overlay_tracks_empty(timeline, base_track_count):
    return all(
        not timeline.GetItemListInTrack("video", t)
        for t in range(base_track_count + 1, timeline.GetTrackCount("video") + 1)
    )

Try / catch

try:
    apply_placements(tl, pool, placements, ...)
except ValueError as e:
    if "overlay tracks must be empty" in str(e):
        target = src.CreateDuplicateTimeline(f"{name}-clean")
        apply_placements(target, pool, placements, ...)
    else:
        raise

Prevention

When it happens

Trigger: Calling apply_placements on a duplicated timeline where users had already placed clips on upper video tracks (e.g. graphics or text on V2/V3), or re-running apply_placements a second time against the same target after the first run already appended overlays.

Common situations: Re-running the tool after a partial failure (retry against a dirty target); duplicating a timeline that includes title/graphics layers; forgetting to clean overlay tracks between runs.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


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

Appendix: source

Thrown at skills/taste-application/scripts/tasteforge/resolve.py:267

    """
    if source_end_mode not in ("inclusive", "exclusive"):
        raise ValueError("source_end_mode must be inclusive or exclusive")
    if not isinstance(source_timeline, str) or not source_timeline:
        raise ValueError("source_timeline must be explicit")
    name = timeline.GetName()
    if not name or name == source_timeline:
        raise ValueError("target must be a distinct versioned timeline")
    plan = allocate_placements(
        placements, fps=fps, base_track_count=base_track_count, probe=probe
    )
    if _fps(timeline.GetSetting("timelineFrameRate")) != _fps(fps):
        raise ValueError("target timeline fps mismatch")
    count = timeline.GetTrackCount("video")
    if count < base_track_count:
        raise ValueError("base_track_count exceeds target video tracks")
    for track in range(base_track_count + 1, count + 1):
        if _items(timeline, "video", track):
            raise ValueError("target overlay tracks must be empty")
    before = _base_snapshot(timeline, base_track_count)
    for _ in range(count, max(event["track"] for event in plan)):
        old_count = timeline.GetTrackCount("video")
        if (
            not timeline.AddTrack("video")
            or timeline.GetTrackCount("video") != old_count + 1
        ):
            raise RuntimeError("could not create overlay track")
    appended = []
    for event in plan:
        imported = media_pool.ImportMedia([event["asset"]])
        if not imported or len(imported) != 1:
            raise RuntimeError(f"could not import {event['asset']}")
        items = media_pool.AppendToTimeline(
            [
                {
                    "mediaPoolItem": imported[0],
                    "startFrame": 0,

View on GitHub (pinned to 8321021c54)