{"record":{"id":"8d6e27bc4d783914","repo":"BerriAI/litellm","slug":"source-video-has-neither-gcsuri-nor-bytesbase64enc","errorCode":null,"errorMessage":"Source video has neither gcsUri nor bytesBase64Encoded. Cannot edit.","messagePattern":"Source video has neither gcsUri nor bytesBase64Encoded\\. Cannot edit\\.","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/llms/vertex_ai/videos/transformation.py","lineNumber":711,"sourceCode":"            )\n\n        if not prefetched_source_data.get(\"done\", False):\n            raise ValueError(\"Source video generation is not complete yet. Check the video status before editing.\")\n\n        source_response: Final[_VeoOperationResponse] = prefetched_source_data.get(\"response\", {})\n        videos: Final = source_response.get(\"videos\", [])\n        if not videos:\n            raise ValueError(\"No videos found in the completed operation. Cannot edit.\")\n\n        source_video: Final = videos[0]\n        video_input: Final[dict[str, str]] = {}\n        if \"gcsUri\" in source_video:\n            video_input[\"gcsUri\"] = source_video[\"gcsUri\"]\n        elif \"bytesBase64Encoded\" in source_video:\n            video_input[\"bytesBase64Encoded\"] = source_video[\"bytesBase64Encoded\"]\n            video_input[\"mimeType\"] = source_video.get(\"mimeType\", \"video/mp4\")\n        else:\n            raise ValueError(\"Source video has neither gcsUri nor bytesBase64Encoded. Cannot edit.\")\n\n        operation_name: Final = extract_original_video_id(video_id)\n        model: Final = self.extract_model_from_operation_name(operation_name) or \"\"\n\n        instance_dict: Final[dict[str, object]] = {\"prompt\": prompt, \"video\": video_input}\n        request_data: Final[dict[str, object]] = {\"instances\": [instance_dict]}\n\n        if extra_body:\n            extra_body_copy: Final = dict(extra_body)\n            nested_params: Final = extra_body_copy.pop(\"parameters\", None)\n            vertex_params: Final[dict[str, object]] = {}\n            if isinstance(nested_params, dict):\n                vertex_params.update(nested_params)\n            vertex_params.update(extra_body_copy)\n            if vertex_params:\n                request_data[\"parameters\"] = vertex_params\n\n        edit_url: Final = f\"{api_base.rstrip('/')}/{model}:predictLongRunning\"","sourceCodeStart":693,"sourceCodeEnd":729,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/llms/vertex_ai/videos/transformation.py#L693-L729","documentation":"Raised by the Vertex edit request transform when the source video object carries neither 'gcsUri' nor 'bytesBase64Encoded'. The edit request needs the source video as input in one of those two forms; a video entry without both is unusable for editing and LiteLLM refuses to build the request.","triggerScenarios":"Veo returns a completed operation whose videos[0] contains only metadata (e.g. an RAPI/GCS-referenced output requiring a different retrieval step, a new response field name, or a permissions-restricted storage config that omits the URI).","commonSituations":"Google adding new output modalities or renaming fields; enterprise configs where output goes to a Cloud Storage bucket the caller cannot read; partial responses from intermediaries/proxies stripping large fields.","solutions":["Print videos[0] from the raw operation to see which keys it actually contains","Regenerate the source video requesting inline bytes (no Cloud Storage output) so bytesBase64Encoded is returned","If output went to GCS, ensure the service account has storage.objects.get and that the bucket config returns gcsUri","Check for Vertex AI API/version changes if the same request previously worked"],"exampleFix":"# before\nresp = litellm.video_generation(model=\"vertex_ai/veo-3.0-generate-001\", prompt=\"...\", **{})\n# later: edit fails — source has neither gcsUri nor bytesBase64Encoded\n\n# after\n# request inline delivery so the source video carries bytesBase64Encoded\nlitellm.video_edit(video_id=vid, prompt=\"...\", custom_llm_provider=\"vertex_ai\")\n# and when generating: avoid Cloud Storage output, or grant read on the target bucket","handlingStrategy":"try-catch","validationCode":"def source_video_is_editable(operation: dict) -> bool:\n    videos = operation.get(\"response\", {}).get(\"videos\", [])\n    if not videos:\n        return False\n    v = videos[0]\n    return \"gcsUri\" in v or \"bytesBase64Encoded\" in v\n\nif not source_video_is_editable(op):\n    raise RuntimeError(f\"source video lacks usable payload: {op['response']['videos']}\")","typeGuard":"def has_editable_payload(video_entry: dict) -> bool:\n    return \"gcsUri\" in video_entry or \"bytesBase64Encoded\" in video_entry","tryCatchPattern":"try:\n    litellm.video_edit(video_id=vid, prompt=p, custom_llm_provider=\"vertex_ai\")\nexcept ValueError as e:\n    if \"neither gcsUri nor bytesBase64Encoded\" in str(e):\n        # regenerate the source with inline delivery or fix GCS read permissions\n        raise SourceVideoUnusable(vid) from e\n    raise","preventionTips":["Generate source videos with inline output (no GCS) if you plan to edit them","When using GCS output, grant the caller storage.objects.get on the bucket","Validate the source video payload keys before building the edit request"],"tags":["vertex-ai","veo","video-edit","response-shape","gcs"],"backgroundTag":"response-schema-mismatch","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}