affaan-m/ECC · error · ValueError
no-repeat plan requires more unique source clips
Error message
no-repeat plan requires more unique source clips
What it means
After building the unique-source map, `_strict_assign` requires at least one unique media clip per planned frame count. If there are fewer unique sources than frame slots, a strict no-repeat plan is impossible and it raises. This is the count-level failure, distinct from the per-slot capacity failure (937).
Solutions
- Add more unique source clips to the media list
- Shorten the target duration so fewer frame slots are needed
- Switch to a mode that permits repeats if strict no-repeat is not a requirement
- Use a slower shot cadence (longer mean_shot) so fewer slots are planned
Example fix
# before: 2 clips, target needs 5 slots apply_local(media=media2, target=30.0) # after: add clips or reduce target apply_local(media=media5, target=10.0)
Defensive patterns
Strategy: validation
Validate before calling
unique = {norm(c["path"]): c for c in media}
planned = plan_shots(cadence, target)
if len(unique) < len(planned):
raise ValueError("need at least one unique clip per cadence slot") Try / catch
try:
report = apply_local(...)
except ValueError as exc:
if "more unique source clips" in str(exc):
target = shrink_target_to_fit(len(media), cadence, fps)
report = apply_local(...) # retry with shorter target
else:
raise Prevention
- Estimate the number of slots (target / mean_shot) and ensure media count covers it
- Warn users when the strict no-repeat mode has few unique sources
- Shorten target duration or lengthen mean_shot when the media library is small
When it happens
Trigger: Calling `apply_local` with e.g. 2 unique media clips while the target duration and cadence produce 5 frame slots: `len(sources) < len(frame_counts)`.
Common situations: Very long target duration planned from many short shots but only a handful of source clips supplied; user expects clips to loop but the strict no-repeat mode forbids it; media folder only partially copied.
Understand the failure class
Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.
Related errors
- source clip is too short for its no-repeat cadence slot
- no-repeat media must contain unique normalized source paths
- apply_local needs at least one media clip
- asset contains too few frames
- asset requires verified alpha
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/f3ea8dafe19c2665.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/apply.py:91
assigned = boundary
if assigned < target_frames:
frame_counts.append(target_frames - assigned)
rate = timeline.fps_fraction(fps)
sources: dict[str, tuple[dict[str, Any], int]] = {}
for clip in media:
path = str(Path(clip["path"]).expanduser().resolve())
# Floor rational capacity: rounding up could read past the source end.
capacity = math.floor(Fraction(str(clip["duration"])) * rate)
# Accept a boundary serialized as a float only when the frame duration
# itself compares within the supplied duration; no broad epsilon.
if float((capacity + 1) / rate) <= clip["duration"]:
capacity += 1
if path in sources:
raise ValueError("no-repeat media must contain unique normalized source paths")
sources[path] = ({**clip, "path": path}, capacity)
if len(sources) < len(frame_counts):
raise ValueError("no-repeat plan requires more unique source clips")
assignments = []
for (clip, capacity), count in zip(sources.values(), frame_counts):
if capacity < count:
raise ValueError("source clip is too short for its no-repeat cadence slot")
assignments.append((clip, count))
return assignments
def plan_shots(cadence: dict[str, Any], target_duration: float) -> list[float]:
"""Propose shot durations filling ``target_duration`` at this cadence.
Samples from the reference's own shot-length distribution (seeded, like
the recovered ``Cadence.plan_shots``) so the plan inherits rhythm
variance instead of flattening into evenly spaced clips.
"""
target_duration = _positive(target_duration, "target duration")
durations = [View on GitHub (pinned to 8321021c54)