affaan-m/ECC · error · ValueError
asset contains too few frames
Error message
asset contains too few frames: {asset} What it means
tasteforge validates every placement's asset media metadata before allocating it onto the timeline. This error means the asset's probed frame count is lower than the number of frames the placement needs (start-to-end span), so appending it would produce a short or invalid clip.
Solutions
- Shorten the placement (reduce end so required frames <= asset frames)
- Replace the asset with a longer take or loop/extend the source media before importing
- Re-probe the asset to refresh cached metadata if frames changed on disk
- Verify the endpoint convention (inclusive/exclusive) is not inflating the frame count
- Check for fps mismatch causing the frame requirement to be computed at the wrong rate
Example fix
// before
{"asset": "sting.mov", "start": 0, "end": 500} # asset has 240 frames
// after
{"asset": "sting.mov", "start": 0, "end": 240} Defensive patterns
Strategy: validation
Validate before calling
info = probe(asset)
frames_needed = end - start
if info.get("frames", 0) < frames_needed:
raise ValueError(f"asset {asset} has {info.get('frames')} frames, need {frames_needed}") Type guard
def has_enough_frames(info: dict, needed: int) -> bool:
return isinstance(info.get("frames"), int) and info["frames"] >= needed Prevention
- Probe assets at import time and store frame counts in a manifest
- Keep assets longer than the longest overlay span you plan
- Verify inclusive/exclusive end convention once per host to avoid inflated frame needs
- Invalidate metadata caches when media files change
When it happens
Trigger: Calling allocate_placements (via apply_placements or plan) with a placement whose frames requirement, derived from record_frame/start and end, exceeds the probe-reported frame count of the asset (e.g. a 3-second clip placed into a 5-second span).
Common situations: Reusing a short sting/logo asset for a longer overlay; timeline rescaled to a slower fps increasing frame span; metadata cache holding stale frames values; off-by-one from inclusive vs exclusive end conventions inflating required frames.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- apply_local needs at least one media clip
- asset requires verified alpha
- candidate fps/duration/retime ambiguity
- Crop must contain four finite values
- FileNotFoundError(source)
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/fe0767261eb6800a.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/resolve.py:129
raise ValueError("explicit opacity must be finite within 0..100")
composite = _integer(event.get("composite"), "composite")
raw_asset = event.get("asset")
if not isinstance(raw_asset, (str, Path)) or not str(raw_asset):
raise ValueError("asset must be a local regular file")
asset = Path(raw_asset).expanduser().resolve()
if not asset.is_file():
raise ValueError(f"asset must be a local regular file: {asset}")
alpha = event.get("requires_alpha", False)
if not isinstance(alpha, bool):
raise ValueError("requires_alpha must be boolean")
key = str(asset)
if key not in metadata:
metadata[key] = probe(asset)
info = metadata[key]
if _fps(info.get("fps")) != rate:
raise ValueError(f"asset fps differs from timeline: {asset}")
if _integer(info.get("frames"), "asset frames", 1) < frames:
raise ValueError(f"asset contains too few frames: {asset}")
if alpha and info.get("has_alpha") is not True:
raise ValueError(f"asset requires verified alpha: {asset}")
checked.append(
{
"id": identifier,
"asset": key,
"record_frame": start,
"frames": frames,
"opacity": opacity,
"composite": composite,
}
)
if not checked:
raise ValueError("at least one placement is required")
ends, allocated = [], {}
for event in sorted(checked, key=lambda entry: entry["record_frame"]):
index = next(
(i for i, end in enumerate(ends) if end <= event["record_frame"]), len(ends)View on GitHub (pinned to 8321021c54)