invoke-ai/InvokeAI · error · FileNotFoundError

Video at {video_path} reports an invalid duration {duration}

Error message

Video at {video_path} reports an invalid duration {duration}

What it means

probe_video_with_codec validates that the probed duration is a finite, non-negative float. If ffprobe reports NaN, inf, or a negative duration, the function raises FileNotFoundError because the metadata cannot be trusted for thumbnail timing.

Source

Thrown at invokeai/app/util/video_thumbnails.py:433

    (unknown) rather than rejected, matching the decoder's own unknown-fps behavior.
    """
    result = _run_worker(["probe", str(video_path)], timeout)
    if result is None:
        raise FileNotFoundError(f"Unable to open video at {video_path}")
    try:
        width = int(result["width"])
        height = int(result["height"])
        duration = float(result["duration"])
        fps_raw = result.get("fps")
        fps: Optional[float] = float(fps_raw) if fps_raw else None
        codec_raw = result.get("codec")
        codec = str(codec_raw).lower() if codec_raw else None
    except (KeyError, TypeError, ValueError, OverflowError) as e:
        raise FileNotFoundError(f"Unable to open video at {video_path}") from e
    if width <= 0 or height <= 0 or width * height > MAX_VIDEO_FRAME_PIXELS:
        raise FileNotFoundError(f"Video at {video_path} reports invalid dimensions {width}x{height}")
    if not math.isfinite(duration) or duration < 0:
        raise FileNotFoundError(f"Video at {video_path} reports an invalid duration {duration}")
    if fps is not None and (not math.isfinite(fps) or fps <= 0):
        fps = None
    return width, height, duration, fps, codec


def probe_video(
    video_path: Path, timeout: float = VIDEO_DECODE_TIMEOUT_SECONDS
) -> tuple[int, int, float, Optional[float]]:
    """Returns validated video metadata without the codec."""
    width, height, duration, fps, _codec = probe_video_with_codec(video_path, timeout)
    return width, height, duration, fps


def decoder_frame_count(video_path: Path, timeout: float = VIDEO_DECODE_TIMEOUT_SECONDS) -> Optional[int]:
    """Returns the exact decoded frame count, or None if it cannot be determined in time.

    Preferred over a ``duration * fps`` estimate, which can overshoot by one on VFR
    uploads or containers with imprecise metadata; callers fall back to that estimate

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Run ffprobe -show_format <path> to inspect the reported duration.
  2. Remux with ffmpeg (-c copy) or re-encode to regenerate valid duration metadata.
  3. For live/unknown-duration sources, cap the recording to a fixed length before processing.
  4. If needed, estimate duration from packet timestamps instead of the format tag.

Example fix

# before
duration = get_duration(path)  # uses probe_video
# after
try:
    duration = get_duration(path)
except FileNotFoundError:
    duration = None  # handle unknown-duration video explicitly
if duration is None:
    raise ValueError(f"{path}: unknown duration; cannot schedule thumbnails")
Defensive patterns

Strategy: validation

Validate before calling

import subprocess, json
out = subprocess.run(["ffprobe","-v","error","-print_format","json","-show_format",path], capture_output=True)
dur_raw = json.loads(out.stdout or "{}").get("format", {}).get("duration")
try:
    dur = float(dur_raw)
except (TypeError, ValueError):
    raise ValueError(f"{path}: duration missing or non-numeric ({dur_raw!r})")
import math
if not math.isfinite(dur) or dur < 0:
    raise ValueError(f"{path}: invalid duration {dur}")

Type guard

import math
def has_valid_duration(probe: dict) -> bool:
    try:
        d = float(probe["format"]["duration"])
    except (KeyError, TypeError, ValueError):
        return False
    return math.isfinite(d) and d >= 0

Try / catch

try:
    w, h, dur, fps, codec = probe_video(path)
except FileNotFoundError as e:
    dur = fallback_duration_from_packets(path)  # or reject
    if dur is None:
        raise ValueError("video has unknown duration") from e

Prevention

When it happens

Trigger: Calling probe_video on a video whose ffprobe JSON contains duration = 'N/A', NaN, INF, or a negative value — typically live streams, unfinalized recordings, or files with corrupted duration metadata.

Common situations: Live/HLS recordings without a fixed duration, partially downloaded files, webm/matroska containers with missing duration, or corrupt metadata after a crashed encoder.

Related errors


AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29). Data as JSON: /api/errors/db76049ac4d02326. Report an issue: GitHub.