invoke-ai/InvokeAI · error · ValueError

Input video {i} ({self.videos[i].video_name}) decoded to zer

Error message

Input video {i} ({self.videos[i].video_name}) decoded to zero frames.

What it means

Thrown in _iter_joined_frames when a decoder yields 0 frames for input video i during concat. The joiner needs at least one frame to build boundaries; a zero-frame clip makes concatenation impossible. Usually indicates a corrupt, empty, or wrongly-probed source file.

Source

Thrown at invokeai/app/invocations/video_concat.py:279

                frame = np.ascontiguousarray(frame)
                n_frames += 1
                # The clip's first head_want frames are consumed into the boundary blend
                # with the previous clip's tail rather than emitted directly.
                if not head_complete:
                    b_head.append(frame)
                    if len(b_head) == head_want and blend is not None:
                        yield from blend(a_tail, b_head)
                        a_tail = []
                        b_head = []
                        head_complete = True
                    continue
                # Hold back the last tail_keep frames seen so far; anything older is
                # guaranteed not to be part of the next boundary and can be emitted.
                tail_buf.append(frame)
                if len(tail_buf) > tail_keep:
                    yield tail_buf.popleft()
            if n_frames == 0:
                raise ValueError(f"Input video {i} ({self.videos[i].video_name}) decoded to zero frames.")
            if n_frames < head_want + tail_keep:
                raise ValueError(
                    f"Clip {i} has {n_frames} frames but the requested transitions need "
                    f"{head_want} from its head + {tail_keep} from its tail. Lower "
                    f"transition_frames or use longer clips."
                )
            a_tail = list(tail_buf)

View on GitHub (pinned to 0b6a024f2f)

Solutions

  1. Check the clip plays in a normal player and is not empty
  2. Re-encode the clip to a standard codec (H.264) before concat
  3. Remove/replace the zero-frame clip in the videos list
  4. Verify the file path resolved by context.videos.get_path points to a real non-empty file

Example fix

// before
videos=[VideoField(video_name='corrupt.mp4')]  # decodes to 0 frames
// after
ffmpeg -i corrupt.mp4 -c:v libx264 fixed.mp4
videos=[VideoField(video_name='fixed.mp4')]
Defensive patterns

Strategy: validation

Validate before calling

import subprocess
n = subprocess.run(['ffprobe','-v','error','-select_streams','v:0','-count_frames','-show_entries','stream=nb_read_frames','-of','csv=p=0', path], capture_output=True, text=True)
if not n.stdout.strip() or n.stdout.strip() == '0':
    raise ValueError(f'{path} decodes to zero frames')

Type guard

def has_frames(probe_result) -> bool:
    return bool(probe_result and probe_result.get('nb_read_frames', 0) > 0)

Try / catch

try:
    out = concat.invoke(context)
except ValueError as e:
    if 'decoded to zero frames' in str(e):
        videos = [v for v in videos if not is_empty_clip(v)]
        out = rebuild(videos).invoke(context)
    else:
        raise

Prevention

When it happens

Trigger: invoke() -> _iter_joined_frames iterates video i; after the decode loop n_frames == 0 (decoder returned no frames).

Common situations: Empty or truncated video files in the input list; codec the decoder cannot handle; broken download producing a header-only file.

Related errors


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