affaan-m/ECC · error · ValueError
target must be a distinct versioned timeline
Error message
target must be a distinct versioned timeline
What it means
The target timeline must have a non-empty name and must not be the same timeline as the source. The library enforces editing onto a distinct versioned copy so the source master timeline is never mutated. It reads the target's name via GetName() and rejects it if empty or equal to source_timeline.
Solutions
- Duplicate the timeline first (Timeline.DuplicateTimeline or CreateCompound/Save as version) and pass the new timeline object
- Compare timeline.GetName() to source_timeline in your script before calling and fail fast with a clearer message
- Set an explicit name on the target timeline in Resolve
- Ensure your clone/apply plumbing passes the duplicate, not the source
Example fix
// before apply_placements(timeline, pool, placements, source_timeline=timeline.GetName(), ...) # same timeline // after dup = pm.ImportTimeline(source_path) or timeline_media_pool.DuplicateTimeline(timeline) apply_placements(dup, pool, placements, source_timeline=timeline.GetName(), ...)
Defensive patterns
Strategy: validation
Validate before calling
name = timeline.GetName()
if not name or name == source_timeline:
raise ValueError("duplicate the source timeline and pass the copy as target") Type guard
def is_distinct_target(timeline, source_name: str) -> bool:
name = timeline.GetName()
return isinstance(name, str) and bool(name) and name != source_name Try / catch
try:
apply_placements(target, pool, ...)
except ValueError as exc:
if "distinct versioned timeline" in str(exc):
print("Duplicate the source timeline before applying placements")
raise Prevention
- Always duplicate the source timeline before automated edits
- Name duplicated timelines explicitly (e.g. master_v4_overlay)
- Assert target name differs from source in your pipeline script
- Never pass the master timeline handle as the apply target
When it happens
Trigger: Passing the source timeline object itself as the target; a timeline whose GetName() returns None/empty (unnamed or detached timeline); typo making both name arguments identical.
Common situations: Automation that clones timelines but still passes the original object; Resolve timelines created via API without a name set; scripts that lost track of which handle is the duplicate.
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
- clip has no 'path
- clip has no 'path
- clip ( ) has non-positive duration
- clip ( ) has non-positive duration
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/62dcbe4c41e3be77.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/resolve.py:256
source_end_mode,
fps,
base_track_count,
probe=probe_asset,
):
"""Append and verify overlays; returns an in-memory placement receipt only.
This does not save/export/render a project. Supply the selected target's
media pool. Existing overlay tracks must be empty; base tracks are preserved.
source_end_mode is required: use the endpoint convention verified on this
Resolve host. No automatic retry occurs if that convention is incorrect.
"""
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
):View on GitHub (pinned to 8321021c54)