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
- Delete or move any clips on video tracks above base_track_count on the target before calling apply_placements.
- Create a fresh duplicate of the source timeline for each run so overlay tracks start empty.
- 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
- Use a fresh duplicate timeline per run; never re-run against a used target.
- Clean up after failed runs or roll back to the duplicate instead of retrying in place.
- Script a pre-check that deletes stray clips above base tracks before applying.
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
- base_track_count exceeds target video tracks
- could not create overlay track
- target timeline fps mismatch
- base tracks changed during overlay placement
- clip has no 'path
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)