{"record":{"id":"5d021e11e98e40de","repo":"BerriAI/litellm","slug":"mavvrik-focus-destination-gcs-session-init-failed","errorCode":null,"errorMessage":"Mavvrik FOCUS destination: GCS session init failed ({init_resp.status_code}): {init_resp.text[:400]}","messagePattern":"Mavvrik FOCUS destination: GCS session init failed \\((.+?)\\): (.+?)","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"litellm/integrations/focus/destinations/mavvrik_destination.py","lineNumber":189,"sourceCode":"        pipeline upstream).\n        \"\"\"\n        gzip_bytes: Final = gzip.compress(content)\n        total: Final = len(gzip_bytes)\n\n        # Step 1: initiate resumable upload session\n        metadata: Final = b'{\"contentEncoding\":\"gzip\",\"contentDisposition\":\"attachment\"}'\n        init_resp: Final = await self._http.client.request(\n            method=\"POST\",\n            url=signed_url,\n            headers={\n                \"Content-Type\": \"application/gzip\",\n                \"x-goog-resumable\": \"start\",\n            },\n            content=metadata,\n            timeout=30.0,\n        )\n        if init_resp.status_code not in (200, 201):\n            raise RuntimeError(\n                f\"Mavvrik FOCUS destination: GCS session init failed ({init_resp.status_code}): {init_resp.text[:400]}\"\n            )\n\n        session_uri: Final = init_resp.headers.get(\"Location\")\n        if not session_uri:\n            raise RuntimeError(\"Mavvrik FOCUS destination: GCS session init missing Location header\")\n        _validate_gcs_url(session_uri, \"session URI\")\n\n        verbose_logger.debug(\n            \"Mavvrik FOCUS destination: GCS session started, uploading %d gzip bytes in %d chunk(s)\",\n            total,\n            max(1, -(-total // _GCS_CHUNK_SIZE)),  # ceiling division\n        )\n\n        # Step 2: upload in chunks; cancel session on any failure to avoid\n        # lingering GCS sessions (they stay open for ~1 week otherwise).\n        offset = 0\n        try:","sourceCodeStart":171,"sourceCodeEnd":207,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/integrations/focus/destinations/mavvrik_destination.py#L171-L207","documentation":"To start a GCS resumable upload, the destination POSTs to the signed URL with x-goog-resumable: start and expects 200/201. Any other status raises RuntimeError with the status and first 400 chars of body. Common embedded statuses: 400 expired/invalid signed URL, 401 token mismatch, 403 permission, 410 URL already consumed.","triggerScenarios":"Delivering when the signed URL expired before use (long gaps between fetching it and uploading), the URL was already used (retries reusing a consumed signed URL), or the metadata/headers are rejected by GCS.","commonSituations":"Large CSVs gzip-compressed slowly so the signed URL (often ~minutes TTL) expires; code that retries the upload step with the same signed URL after a partial failure; clock skew between client and GCS.","solutions":["On 400/expired, re-fetch a fresh signed URL (call the upload-url endpoint again) and restart the upload — the destination does this per delivery, so simply retrying the whole deliver() usually works.","Keep the gap between signed-URL fetch and upload small; gzip first, then fetch the URL, if customizing.","Never reuse a signed URL after a successful session-init — each URL starts one resumable session.","For persistent 403, verify the Mavvrik-issued URL grants resumable-upload permission."],"exampleFix":"# retry whole delivery to get a fresh signed URL on init failure\nfor attempt in range(3):\n    try:\n        await mavvrik_dest.deliver(content=csv, time_window=tw, filename=\"f.csv\")\n        break\n    except RuntimeError as e:\n        if \"GCS session init failed\" not in str(e) or attempt == 2:\n            raise\n        await asyncio.sleep(2 ** attempt)","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"import asyncio\n\nasync def deliver_with_refresh(dest, **kw):\n    for attempt in range(3):\n        try:\n            return await dest.deliver(**kw)\n        except RuntimeError as e:\n            # fresh signed URL on next attempt solves expired/consumed URLs\n            if \"GCS session init failed\" not in str(e) or attempt == 2:\n                raise\n            await asyncio.sleep(2 ** attempt)","preventionTips":["Retry the entire deliver() (not just the upload step) so a fresh signed URL is fetched.","Never cache or reuse signed URLs across retries — each starts exactly one resumable session.","Compress before fetching the URL to minimize the fetch-to-upload gap for large exports."],"tags":["focus","mavvrik","gcs","network","signed-url","retryable"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}