affaan-m/ECC · error · ValueError
source_end_mode must be inclusive or exclusive
Error message
source_end_mode must be inclusive or exclusive
What it means
apply_placements requires source_end_mode to be given explicitly as 'inclusive' or 'exclusive'. Resolve hosts differ in whether the end frame is included in the source range; the library refuses to guess because a wrong guess yields off-by-one readback failures. This is validated before any timeline mutation.
Solutions
- Pass source_end_mode="inclusive" or "exclusive" explicitly after verifying the convention on your Resolve host
- Run the mode-validation tests (test_mode_must_be_explicit_and_valid) to confirm behavior
- Fix wrappers/config to forward only the two allowed strings
- Add a host-verification step in your pipeline that determines the convention once and records it
Example fix
// before apply_placements(timeline, pool, placements, fps=fps, base_track_count=2) // after apply_placements(timeline, pool, placements, fps=fps, base_track_count=2, source_end_mode="exclusive")
Defensive patterns
Strategy: validation
Validate before calling
if source_end_mode not in ("inclusive", "exclusive"):
raise ValueError("source_end_mode must be 'inclusive' or 'exclusive'") Type guard
from typing import Literal
def is_valid_mode(m: str) -> bool:
return m in ("inclusive", "exclusive")
Mode = Literal["inclusive", "exclusive"] Try / catch
try:
apply_placements(..., source_end_mode=mode)
except ValueError as exc:
print(f"Fix source_end_mode: {exc}")
raise Prevention
- Always pass source_end_mode explicitly; never rely on defaults
- Determine the convention on your Resolve host once and store it in config
- Use Literal["inclusive","exclusive"] typing at your call sites
- Add the library's mode-validation tests to your CI
When it happens
Trigger: Calling apply_placements/apply without source_end_mode, or with a value like ' Inclus ive', 'end-exclusive', or None.
Common situations: Copy-pasting an older call signature before the parameter existed; assuming a default; typo'd enum string; writing a generic wrapper that forwards user config unvalidated.
Understand the failure class
Background: "invalid argument", "unknown mode", "not supported": invalid enum-like argument errors explained — this error's family across 19 libraries.
Related errors
- artifact has invalid modality binding
- assigneeKind must be 'agent' or 'human'.
- CV effect has an invalid subject anchor
- explicit candidate review state required
- --host-provider must be anthropic, openai, or unknown
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/f162b3148d52b09f.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/resolve.py:251
timeline,
media_pool,
placements,
*,
source_timeline,
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)):View on GitHub (pinned to 8321021c54)