invoke-ai/InvokeAI · error · ValueError
Video has no decodable frame
Error message
Video has no decodable frame
What it means
Raised by _probe_decodable_video in invokeai/app/api/routers/videos.py:234-235 when extract_video_frame returns None for frame_index=0 without timing out. ffprobe read the container and codec fine, but no first frame could actually be decoded — the video is structurally valid but has no renderable picture data. The ValueError is caught by upload_video and returned as HTTP 415 'Failed to read video'.
Source
Thrown at invokeai/app/api/routers/videos.py:235
def _probe_decodable_video(path: Path) -> tuple[tuple[int, int, float, Optional[float]], Optional[PILImage.Image]]:
"""Probes metadata and proves the video has a decodable first frame.
Returns the metadata plus the decoded frame so the save path can reuse it as the
thumbnail source instead of spawning another decode worker. A decode timeout is
contention on a loaded server, not evidence the video is bad — probe_video already
succeeded — so it yields (metadata, None) and the upload proceeds, with save-time
thumbnail extraction as the backstop.
"""
width, height, duration, fps, codec = probe_video_with_codec(path)
if codec is None or codec.lower() not in {"h264", "avc", "avc1", "libx264"}:
raise ValueError("Video must use a browser-compatible H.264/AVC codec")
metadata = (width, height, duration, fps)
try:
first_frame = extract_video_frame(path, frame_index=0, raise_on_timeout=True)
except VideoDecodeTimeoutError:
return metadata, None
if first_frame is None:
raise ValueError("Video has no decodable frame")
return metadata, first_frame
@videos_router.post(
"/upload",
operation_id="upload_video",
responses={
201: {"description": "The video was uploaded successfully"},
415: {"description": "Video upload failed"},
},
status_code=201,
response_model=VideoDTO,
)
async def upload_video(
current_user: CurrentUserOrDefault,
file: UploadFile,
request: Request,
response: Response,View on GitHub (pinned to 0b6a024f2f)
Solutions
- Re-obtain or re-export the video file — the frame data itself is corrupt, remuxing will not help
- Re-encode fully with ffmpeg -i input.mp4 -c:v libx264 -pix_fmt yuv420p output.mp4; if ffmpeg also errors, the source is unrecoverable
- Verify the download completed: compare file size/checksum with the source, and confirm the MP4 has a moov box (ffmpeg -v error -i input.mp4 -f null -)
- If serving from object storage, confirm the upload to storage was complete before passing the file on
Example fix
// before: passing a partially-downloaded file straight to the API await api.upload_video(truncated_file) // after: verify decodability first subprocess.run(["ffmpeg", "-v", "error", "-i", path, "-f", "null", "-"], check=True) await api.upload_video(open(path, "rb"))
Defensive patterns
Strategy: validation
Validate before calling
import subprocess
def decodes_without_error(path):
r = subprocess.run(["ffmpeg", "-v", "error", "-i", path, "-f", "null", "-"],
capture_output=True, text=True)
return r.returncode == 0 and r.stderr.strip() == "" Type guard
def has_decodable_first_frame(first_frame) -> bool:
return first_frame is not None Try / catch
try:
await client.upload_video(f)
except httpx.HTTPStatusError as e:
if e.response.status_code == 415:
raise RuntimeError("Video has no decodable frame; re-export or re-download the file") from e
raise Prevention
- Verify checksums after downloads to catch truncation
- Run ffmpeg -v error -i file -f null - locally before uploading to detect corrupt streams
- Never concatenate MP4s with cat; use ffmpeg concat demuxer
- Ensure the encoding process completed before distributing the file
When it happens
Trigger: POST /v1/videos/upload with an MP4 that has a valid container/codec but undecodable frame data: truncated mdat (incomplete download), corrupted or missing moov/sync samples, a video track whose samples are all corrupt, or a zero-length/empty video stream.
Common situations: Downloads interrupted mid-transfer, files produced by a crashed encoder, heavily damaged storage media, files that were concatenated incorrectly, or synthetic/test files with valid headers but no actual compressed frames.
Related errors
- Video must use a browser-compatible H.264/AVC codec
- Decoded only {num_frames} of {expected_frames} requested fra
- Unable to validate video dimensions for {video_path}
- Video dimensions {width}x{height} exceed the maximum decodab
- Unable to open video at {video_path}
AI-assisted analysis of invoke-ai/InvokeAI@0b6a024f2f (2026-08-29).
Data as JSON: /api/errors/3a81472a8d437b5b.
Report an issue: GitHub.