calesthio/OpenMontage · error · RuntimeError
Files API failed to process the uploaded video
Error message
Files API failed to process the uploaded video
What it means
Raised when the Google Files API reports state=FAILED for an uploaded video. The Files API validates and transcodes uploads asynchronously; if the media is rejected (corrupt, unsupported, or violates policy) the file transitions from PROCESSING to FAILED instead of ACTIVE, and the tool raises RuntimeError before ever using the file.
Source
Thrown at tools/video/gemini_omni_video.py:275
)
upload_resp.raise_for_status()
file_info = upload_resp.json().get("file", {})
# Wait until the uploaded video is processed before referencing it.
deadline = time.time() + _MAX_POLL_SECONDS
while str(file_info.get("state", "")).upper() == "PROCESSING":
if time.time() > deadline:
raise TimeoutError("Uploaded video did not finish processing in time")
time.sleep(_POLL_INTERVAL_SECONDS)
status_resp = requests_mod.get(
f"{_BASE_URL}/{file_info.get('name')}",
headers={"x-goog-api-key": api_key},
timeout=15,
)
status_resp.raise_for_status()
file_info = status_resp.json()
if str(file_info.get("state", "")).upper() == "FAILED":
raise RuntimeError("Files API failed to process the uploaded video")
uri = file_info.get("uri")
if not uri:
raise RuntimeError(f"Files API response missing uri: {file_info}")
return uri
@staticmethod
def _extract_output_video(data: dict[str, Any]) -> dict[str, Any] | None:
"""Find the output video payload ({'data': b64} or {'uri': files/...})."""
for key in ("output_video", "outputVideo"):
video = data.get(key)
if isinstance(video, dict) and (video.get("data") or video.get("uri")):
return video
# REST responses may also carry the video inside steps[].content[].
for step in data.get("steps") or []:
for item in step.get("content") or []:
if isinstance(item, dict) and (item.get("data") or item.get("uri")):
if "video" in str(item.get("type", "")).lower() or item.get("mime_type", "").startswith("video/"):View on GitHub (pinned to 95e1c3d0ab)
Solutions
- Verify the source file plays locally (ffprobe/quick look) and is not truncated, then re-upload.
- Re-encode to H.264 MP4 with AAC audio — the most reliably supported format for the Files API.
- Check the file size matches expectation before passing it in; reject zero-byte files upstream.
- If the file is valid and small, inspect the file's error details via the Files API status response for a specific reason.
- Retry once — occasional transient transcode failures do occur.
Example fix
// before
{"video_path": "clip.mov"} // ProRes 4444, Files API marks FAILED
// after (shell)
ffmpeg -i clip.mov -c:v libx264 -pix_fmt yuv420p -c:a aac clip.mp4
// then
{"video_path": "clip.mp4"} Defensive patterns
Strategy: validation
Validate before calling
from pathlib import Path
import subprocess
def validate_video_for_files_api(path: str) -> None:
p = Path(path)
if p.stat().st_size == 0:
raise ValueError("empty file will be marked FAILED")
subprocess.run(
["ffprobe", "-v", "error", "-select_streams", "v:0", "-show_entries",
"stream=codec_name", "-of", "csv=p=0", str(p)],
check=True, capture_output=True,
) # unreadable stream -> non-zero exit, don't upload Try / catch
try:
result = gemini_omni_video(inputs)
except RuntimeError as e:
if "failed to process the uploaded video" in str(e).lower():
inputs = {**inputs, "video_path": reencode_h264(inputs["video_path"])}
result = gemini_omni_video(inputs) # one retry with clean encoding
else:
raise Prevention
- Always upload H.264/AAC MP4 — most reliably accepted by the Files API.
- Never pass files whose size is 0 or differs from what your pipeline wrote.
- Treat one FAILED as a media problem first: fix the file, not the deadline.
When it happens
Trigger: After a video upload, the polling loop exits with file_info.state == 'FAILED' on the status GET to {BASE_URL}/{file.name}. Caused by corrupt/truncated uploads, unsupported codecs, or content rejected by Google's media pipeline.
Common situations: Truncated upload (network drop mid-PUT so the stored bytes are invalid); unsupported container/codec (e.g. some ProRes/HEVC variants); zero-byte file passed by mistake; policy-flagged content; partial disk write left an incomplete file.
Related errors
- Uploaded video did not finish processing in time
- Files API did not return an upload URL
- Files API response missing uri: {file_info}
- This Gemini route requires at least one reference image
- Gemini Omni developer reference_to_video requires exactly on
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/ae44c7ce27a11165.
Report an issue: GitHub.