BerriAI/litellm · error · ValueError
Failed to parse operation response
Error message
Failed to parse operation response: {e} What it means
Thrown by transform_video_create_response after litellm.video_generation() returns from the Gemini (Veo) endpoint. The raw JSON body failed Pydantic validation against GeminiLongRunningOperationResponse, meaning Google returned a body whose fields are missing, unexpected, or of the wrong type (e.g. an error payload instead of an operation object). The original Pydantic message is embedded in '{e}', so it names the exact offending field.
Solutions
- Run with litellm.set_verbose = True (or LITELLM_LOG=DEBUG) and inspect the raw response body contained in nearby logs to see what Google actually returned.
- Upgrade litellm to the latest release (pip install -U litellm) so the GeminiLongRunningOperationResponse model matches the current Veo schema.
- If the body is an error payload, fix the underlying cause (API key, quota, invalid model name, safety rejection) before retrying.
- If the payload looks like a valid Veo operation but still fails to parse, open a litellm GitHub issue with the sanitized JSON so the Pydantic model can be updated.
Example fix
# before
video = litellm.video_generation(model="gemini/veo-3", prompt="a cat surfing")
# after
try:
video = litellm.video_generation(model="gemini/veo-3", prompt="a cat surfing")
except ValueError as e:
if "Failed to parse operation response" in str(e):
litellm.print_verbose(f"Veo returned an unparseable body: {e}")
raise Defensive patterns
Strategy: try-catch
Try / catch
try:
video = litellm.video_generation(model="gemini/veo-3", prompt=prompt)
except ValueError as e:
if "Failed to parse operation response" in str(e):
# unexpected Veo payload: log for triage, do not retry blindly
logger.error("veo schema mismatch: %s", e)
raise
raise Prevention
- Pin a known-good litellm version and upgrade deliberately after checking Veo release notes.
- Enable LITELLM_LOG=DEBUG in staging so raw provider payloads are captured when parse errors appear.
- Wrap provider calls in a thin adapter so schema failures surface as one actionable error type in your app.
When it happens
Trigger: Calling litellm.video_generation(model='gemini/veo-3', ...) (or any 'gemini/' Veo model) where the API responds with a body that does not match the long-running-operation schema: an error JSON returned with HTTP 200, a proxy/gateway rewriting the payload, or a Veo schema change not yet modeled in your installed litellm version.
Common situations: Outdated litellm package after Google changed the Veo response shape; a corporate proxy returning an HTML/JSON error page; quota or safety errors delivered in a non-operation envelope; mocked/stubbed test servers returning minimal JSON.
Understand the failure class
Background: Schema validation failed / invalid input schema: payload rejected because its shape doesn't match the expected schema — this error's family across 28 libraries.
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- Failed to extract video data
- No base64 encoded video data found
- No operation name in Veo response
- No operation name in Veo response
- No video data found in completed operation
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/0b98910896355c25.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/llms/gemini/videos/transformation.py:321
{
"name": "operations/generate_1234567890",
"metadata": {...},
"done": false,
"error": {...}
}
We return this as a VideoObject with:
- id: operation name (used for polling)
- status: "processing"
- usage: includes duration_seconds and optional video_resolution for cost calculation
"""
response_data: Final = raw_response.json()
# Parse response using Pydantic model for type safety
try:
operation_response: Final = GeminiLongRunningOperationResponse(**response_data)
except Exception as e:
raise ValueError(f"Failed to parse operation response: {e}")
operation_name: Final = operation_response.name
if not operation_name:
raise ValueError(f"No operation name in Veo response: {response_data}")
if custom_llm_provider:
video_id = encode_video_id_with_provider(operation_name, custom_llm_provider, model)
else:
video_id = operation_name
video_obj: Final = VideoObject(
id=video_id,
object="video",
status="processing",
model=model,
)
usage_data: Final[dict[str, Any]] = {}View on GitHub (pinned to 77b7c6c40c)