affaan-m/ECC · error · ValueError
Invalid media duration
Error message
Invalid media duration: {path.name} What it means
For each input video, export_draft calls probe(path) to get its duration and rejects any duration that is not a finite positive number. Non-finite (NaN/inf), zero, or negative durations indicate unreadable or corrupt media, or a broken probe backend.
Solutions
- Verify the file plays and ffprobe reports a duration: ffprobe -v error -show_entries format=duration <file>
- Remove or re-download the corrupt/offending file (the message includes its name)
- If passing a custom probe, ensure it returns a finite float > 0 and raises on unreadable media
- Confirm the input is a video, not an image or audio-only file without duration
Example fix
// before
def probe(path): return None # stub
export_draft(files, name='edit', probe=probe)
// after
def probe(path):
out = subprocess.run(['ffprobe','-v','error','-show_entries','format=duration',
'-of','csv=p=0',str(path)], capture_output=True, text=True, check=True)
return float(out.stdout.strip()) Defensive patterns
Strategy: validation
Validate before calling
def duration_ok(d):
return isinstance(d, (int, float)) and math.isfinite(d) and d > 0
for f in files:
d = probe(Path(f).resolve(strict=True))
if not duration_ok(d):
raise ValueError(f'{f}: probe returned invalid duration {d!r}') Type guard
def has_valid_duration(d):
return isinstance(d, (int, float)) and not isinstance(d, bool) and math.isfinite(d) and d > 0 Try / catch
try:
export_draft(files, name=name)
except ValueError as e:
if 'Invalid media duration' in str(e):
bad = str(e).split(': ')[-1]
sys.exit(f're-encode or remove corrupt media: {bad}') Prevention
- Pre-flight every input with ffprobe before export
- Check for zero-byte or partially downloaded files
- If injecting a custom probe, test it against corrupt and non-media files
- Re-encode problem files: ffmpeg -i in.mp4 -c copy fixed.mp4
When it happens
Trigger: A video file that ffprobe cannot read (corrupt file, unsupported codec), a custom probe callable returning None/NaN/0/negative, or files that resolve but are not actual media.
Common situations: Zero-byte or partially downloaded video files; image files passed instead of videos; a stubbed probe in tests/CI where ffprobe is missing and returns garbage; media with missing duration metadata in unusual containers.
Understand the failure class
Background: "invalid duration" / "failed to parse duration": why your timeout, interval, or TTL string is rejected and which formats each library accepts — this error's family across 32 libraries.
Related errors
- is outside its source duration
- probe duration is not bound to source duration
- application bundle differs from its bound evidence
- apply_local needs at least one media clip
- asset contains too few frames
AI-assisted analysis of affaan-m/ECC@8321021c54 (2026-09-16).
Data as JSON: /api/errors/e7c824067632624d.
Report an issue: GitHub.
Appendix: source
Thrown at skills/taste-application/scripts/tasteforge/media/capcut.py:69
overwrite=False,
cc=None,
probe=duration_of,
):
geometry(width, height, fps)
if overwrite:
raise ValueError("CapCut draft replacement is unsafe; choose a new name")
if not re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_. -]{0,99}", name) or name.endswith(
"."
):
raise ValueError("Draft name must be a plain file name")
if not files:
raise ValueError("At least one video is required")
prepared = []
for filename in files:
path = Path(filename).resolve(strict=True)
duration = probe(path)
if not math.isfinite(duration) or duration <= 0:
raise ValueError(f"Invalid media duration: {path.name}")
prepared.append((str(path), duration))
if cc is None:
import pycapcut as cc
folder = cc.DraftFolder(str(drafts))
script = folder.create_draft(name, width, height, fps=fps, allow_replace=False)
script.add_track(cc.TrackType.video)
elapsed = 0
for filename, duration in prepared:
script.add_segment(
cc.VideoSegment(filename, cc.trange(f"{elapsed:.6f}s", f"{duration:.6f}s"))
)
elapsed += duration
script.save()
return {"name": name, "segments": len(prepared), "duration": elapsed, "saved": True}
def main(argv=None):
parser = argparse.ArgumentParser(description=__doc__)View on GitHub (pinned to 8321021c54)