BerriAI/litellm · error · ValueError
Error parsing file upload response
Error message
Error parsing file upload response: {e} What it means
Thrown by GoogleAIStudioFilesHandler.transform_create_file_response after a Gemini Files API upload request completes. The handler does raw_response.json(), builds GeminiCreateFilesResponseObject from response_json['file'], then reads uri, sizeBytes, createTime (parsed via time.strptime with '%Y-%m-%dT%H:%M:%S.%f%z') and displayName to build an OpenAIFileObject. Any failure in that chain (non-JSON body, missing key, Pydantic validation error, unparseable timestamp) is caught, logged with a full traceback via verbose_logger.exception, and re-raised wrapped in this ValueError.
Solutions
- Enable verbose logging (litellm.set_verbose=True or LITELLM_LOG=DEBUG) and read the verbose_logger.exception traceback plus the wrapped '{e}' to see exactly which field/step failed
- Inspect the raw response body: the logged exception shows whether the JSON lacks file.uri/sizeBytes/createTime/displayName or whether .json() itself failed
- If a proxy/gateway is set via api_base or GEMINI_API_BASE, bypass it or confirm it forwards Gemini's JSON responses unmodified
- Upgrade litellm to the latest patch release to pick up any parser fixes for Gemini Files API changes
- As a workaround, upload files with the google-genai SDK and pass the resulting file URI into the Gemini chat request
Example fix
# before
file_obj = litellm.create_file(file=open('doc.pdf', 'rb'), custom_llm_provider='gemini')
# ValueError: Error parsing file upload response: 'uri'
# after - surface the real cause and verify the payload shape first
import litellm
litellm.set_verbose = True # traceback shows the underlying KeyError/validation error
try:
file_obj = litellm.create_file(
file=open('doc.pdf', 'rb'),
custom_llm_provider='gemini',
api_key=GEMINI_KEY,
)
except ValueError as e:
raise RuntimeError(f'Gemini upload failed, inspect verbose log: {e}') from e Defensive patterns
Strategy: try-catch
Validate before calling
import litellm
from litellm.llms.gemini.common_utils import GeminiModelInfo
if not (litellm.params.api_key if hasattr(litellm, 'params') else None) and not GeminiModelInfo.get_api_key():
raise RuntimeError('Set GEMINI_API_KEY/GOOGLE_API_KEY before uploading files') Try / catch
try:
f = litellm.create_file(file=fp, custom_llm_provider='gemini', api_key=KEY)
except ValueError as e:
if 'Error parsing file upload response' in str(e):
# {e} suffix carries the underlying KeyError/ValidationError/json error
log.exception('gemini upload parse failed: %s', e)
raise
raise Prevention
- Keep litellm updated so Gemini Files response-shape fixes land automatically
- Point api_base only at proxies proven to pass Google JSON through untouched
- Run with LITELLM_LOG=DEBUG during file-flow integration so wrapped parse errors show their true cause
- Persist the create_file response id immediately; do not re-derive it by re-parsing
When it happens
Trigger: litellm.create_file(..., custom_llm_provider='gemini') where the upload endpoint returns an error payload instead of a 'file' object; a file object missing uri/sizeBytes/createTime/displayName; a createTime that does not match the strict '%Y-%m-%dT%H:%M:%S.%f%z' format (e.g. no fractional seconds or an unexpected timezone suffix); or HTML/plain-text from a proxy configured via api_base/GEMINI_API_BASE.
Common situations: Custom GEMINI_API_BASE pointing at a gateway that returns HTML error pages; free-tier quota or API-not-enabled errors returned after the upload handshake; Gemini Files API schema drift on newer litellm versions; large-file uploads that were cut off server-side, producing a truncated body.
Related errors
- Error parsing file delete response
- Error parsing file retrieve response
- Failed to delete file
- Failed to parse operation response
- GoogleAIStudioFilesHandler does not support file content…
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/2ae7c3b4442840c5.
Report an issue: GitHub.
Appendix: source
Thrown at litellm/llms/gemini/files/transformation.py:192
id=response_object["uri"], # Gemini uses URI as identifier
bytes=int(response_object["sizeBytes"]), # Gemini doesn't return file size
created_at=int(
time.mktime(
time.strptime(
response_object["createTime"].replace("Z", "+00:00"),
"%Y-%m-%dT%H:%M:%S.%f%z",
)
)
),
filename=response_object["displayName"],
object="file",
purpose="user_data", # Default to assistants as that's the main use case
status="uploaded",
status_details=None,
)
except Exception as e:
verbose_logger.exception("Error parsing file upload response: %s", e)
raise ValueError(f"Error parsing file upload response: {e}")
def transform_retrieve_file_request(
self,
file_id: str,
optional_params: dict,
litellm_params: dict,
) -> tuple[str, dict]:
"""
Get the URL to retrieve a file from Google AI Studio.
Endpoint:
GET https://generativelanguage.googleapis.com/v1beta/{name=files/*}
The URL should look like:
https://generativelanguage.googleapis.com/v1beta/files/{file_id}?key=API_KEY
We expect file_id to be just the file identifier (e.g., files/abc123 or abc123)
as returned by the upload response. (If it's a full URL, extract the file name.)View on GitHub (pinned to 77b7c6c40c)