calesthio/OpenMontage · error · RuntimeError
Files API response missing uri: {file_info}
Error message
Files API response missing uri: {file_info} What it means
Raised when a Files API file record reaches a non-PROCESSING, non-FAILED state but contains no 'uri' field. After the poll loop, the tool unconditionally reads file_info['uri'] to build the reference for generation; a missing uri means the API returned an unexpected response shape and the tool cannot proceed safely, so it embeds the whole file_info dict in the error.
Source
Thrown at tools/video/gemini_omni_video.py:279
# 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/"):
return item
if item.get("data") or str(item.get("uri", "")).startswith("files/"):
return item
return NoneView on GitHub (pinned to 95e1c3d0ab)
Solutions
- Retry the request — if the response body was a transient error page that parsed as JSON, a fresh call returns the normal shape.
- Print/log the full file_info from the error message to identify the actual state and response shape returned.
- Check for an OpenMontage update — if Google renamed/moved the uri field, a patched tool version is likely needed.
- Verify no corporate proxy or gateway is modifying API responses.
Defensive patterns
Strategy: retry
Try / catch
try:
result = gemini_omni_video(inputs)
except RuntimeError as e:
if "missing uri" in str(e):
# response-shape drift or transient odd body: one retry, then surface
result = gemini_omni_video(inputs)
else:
raise Prevention
- Pin to a known-good OpenMontage version so Files API schema drift is patched centrally.
- Keep the full file_info from the exception — it is the only evidence of what the API returned.
- Avoid network middleboxes that rewrite API response bodies.
When it happens
Trigger: The status GET returns 200 with state neither PROCESSING nor FAILED (expected 'ACTIVE') yet the JSON body lacks a top-level 'uri' key — e.g. an API version change, an error payload shaped differently, or a new intermediate state that exits the loop.
Common situations: Google changes the Files API response schema (uri renamed or nested); a state like 'STATE_UNSPECIFIED' that falls through both checks; a proxy/gateway stripping response fields; relying on undocumented response shapes that shift without notice.
Related errors
- Kling Classic create response missing data.task_id: {data}
- Files API did not return an upload URL
- Uploaded video did not finish processing in time
- Files API failed to process the uploaded video
- TokenHub submit returned no task id: {data}
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/b73792d60890ef34.
Report an issue: GitHub.