{"record":{"id":"176908558288fafc","repo":"BerriAI/litellm","slug":"video-generation-is-not-complete-yet-please-check-176908","errorCode":null,"errorMessage":"Video generation is not complete yet. Please check status with video_status() before downloading.","messagePattern":"Video generation is not complete yet\\. Please check status with video_status\\(\\) before downloading\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"litellm/llms/vertex_ai/videos/transformation.py","lineNumber":547,"sourceCode":"        Since we need to make an HTTP call here, we'll use the same fetchPredictOperation\n        approach as status retrieval.\n        \"\"\"\n        return self.transform_video_status_retrieve_request(video_id, api_base, litellm_params, headers)\n\n    def transform_video_content_response(\n        self,\n        raw_response: httpx.Response,\n        logging_obj: LiteLLMLoggingObj,\n    ) -> bytes:\n        \"\"\"\n        Transform the Veo video content download response.\n\n        Extracts the base64 encoded video from the response and decodes it to bytes.\n        \"\"\"\n        response_data: Final = _parse_veo_operation(raw_response)\n\n        if not response_data.get(\"done\", False):\n            raise ValueError(\n                \"Video generation is not complete yet. Please check status with video_status() before downloading.\"\n            )\n\n        try:\n            video_response: Final = response_data.get(\"response\", {})\n            videos: Final = video_response.get(\"videos\", [])\n\n            if not videos or len(videos) == 0:\n                raise ValueError(\"No video data found in completed operation\")\n\n            # Get the first video\n            video_data: Final = videos[0]\n            base64_encoded: Final = video_data.get(\"bytesBase64Encoded\")\n\n            if not base64_encoded:\n                raise ValueError(\"No base64 encoded video data found\")\n\n            # Decode base64 to bytes","sourceCodeStart":529,"sourceCodeEnd":565,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/llms/vertex_ai/videos/transformation.py#L529-L565","documentation":"Raised when downloading Veo video content if the polled operation still has `done: false`. Veo generation is asynchronous — the initial call returns an operation, and content retrieval via transform_video_content is only valid after the operation completes. This error is a guard telling you the download was attempted too early; poll video_status() until done before fetching bytes.","triggerScenarios":"Calling aretrieve_video_content / content download immediately after video_generation returns (status \"processing\"), or before the video_status() poll shows done=true; long generations (30-60s+) interrupted by an early fixed-delay download.","commonSituations":"Using a fixed sleep(10) then download instead of polling; treating the generation response as synchronous; retry loops that skip the status check.","solutions":["Poll until completion: loop on video_status(video_id=...) and only download when status shows done (status \"completed\").","Respect the polling pattern: Veo operations take tens of seconds to minutes; add exponential backoff between polls (e.g. 5s, 10s, 20s).","Check for an error field in the status response — failed operations never become done and should be surfaced as a failure, not retried for download.","If you need a blocking API, wrap generation + poll + download in one helper instead of calling download directly."],"exampleFix":"# before\nresult = litellm.video_generation(model=\"vertex_ai/veo-2.0-generate-001\", prompt=p, vertex_project=proj)\nimport time; time.sleep(10)\ncontent = litellm.retrieve_video_content(video_id=result.id)  # may raise: not done\n\n# after\nresult = litellm.video_generation(model=\"vertex_ai/veo-2.0-generate-001\", prompt=p, vertex_project=proj)\nwhile True:\n    status = litellm.video_status(video_id=result.id, vertex_project=proj)\n    if status.status == \"completed\":\n        break\n    if status.status == \"failed\":\n        raise RuntimeError(status)\n    time.sleep(10)\ncontent = litellm.retrieve_video_content(video_id=result.id, vertex_project=proj)","handlingStrategy":"retry","validationCode":"def wait_for_veo(video_id: str, project: str, timeout_s: int = 600) -> None:\n    deadline = time.time() + timeout_s\n    while time.time() < deadline:\n        st = litellm.video_status(video_id=video_id, vertex_project=project)\n        if st.status == \"completed\":\n            return\n        if st.status == \"failed\":\n            raise RuntimeError(f\"veo operation failed: {st}\")\n        time.sleep(10)\n    raise TimeoutError(\"veo generation did not finish in time\")","typeGuard":null,"tryCatchPattern":"try:\n    content = litellm.retrieve_video_content(video_id=vid, vertex_project=proj)\nexcept ValueError as e:\n    if \"not complete yet\" in str(e):\n        time.sleep(15)  # then re-poll; or treat as signal to extend the polling loop\n        content = litellm.retrieve_video_content(video_id=vid, vertex_project=proj)\n    else:\n        raise","preventionTips":["Never download without a preceding status check showing done/completed.","Encapsulate submit -> poll (with backoff) -> download in a single helper so callers can't skip steps.","Treat 'failed' status as terminal — don't keep polling or retry downloads."],"tags":["vertex-ai","veo","video-generation","async-operation","polling"],"backgroundTag":"async-operation-not-complete","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}