BerriAI/litellm · error · RuntimeError

Mavvrik FOCUS destination: GCS session init failed ({init_re

Error message

Mavvrik FOCUS destination: GCS session init failed ({init_resp.status_code}): {init_resp.text[:400]}

What it means

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.

Source

Thrown at litellm/integrations/focus/destinations/mavvrik_destination.py:189

        pipeline upstream).
        """
        gzip_bytes: Final = gzip.compress(content)
        total: Final = len(gzip_bytes)

        # Step 1: initiate resumable upload session
        metadata: Final = b'{"contentEncoding":"gzip","contentDisposition":"attachment"}'
        init_resp: Final = await self._http.client.request(
            method="POST",
            url=signed_url,
            headers={
                "Content-Type": "application/gzip",
                "x-goog-resumable": "start",
            },
            content=metadata,
            timeout=30.0,
        )
        if init_resp.status_code not in (200, 201):
            raise RuntimeError(
                f"Mavvrik FOCUS destination: GCS session init failed ({init_resp.status_code}): {init_resp.text[:400]}"
            )

        session_uri: Final = init_resp.headers.get("Location")
        if not session_uri:
            raise RuntimeError("Mavvrik FOCUS destination: GCS session init missing Location header")
        _validate_gcs_url(session_uri, "session URI")

        verbose_logger.debug(
            "Mavvrik FOCUS destination: GCS session started, uploading %d gzip bytes in %d chunk(s)",
            total,
            max(1, -(-total // _GCS_CHUNK_SIZE)),  # ceiling division
        )

        # Step 2: upload in chunks; cancel session on any failure to avoid
        # lingering GCS sessions (they stay open for ~1 week otherwise).
        offset = 0
        try:

View on GitHub (pinned to 6c2dcb801b)

Solutions

  1. 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.
  2. Keep the gap between signed-URL fetch and upload small; gzip first, then fetch the URL, if customizing.
  3. Never reuse a signed URL after a successful session-init — each URL starts one resumable session.
  4. For persistent 403, verify the Mavvrik-issued URL grants resumable-upload permission.

Example fix

# retry whole delivery to get a fresh signed URL on init failure
for attempt in range(3):
    try:
        await mavvrik_dest.deliver(content=csv, time_window=tw, filename="f.csv")
        break
    except RuntimeError as e:
        if "GCS session init failed" not in str(e) or attempt == 2:
            raise
        await asyncio.sleep(2 ** attempt)
Defensive patterns

Strategy: retry

Try / catch

import asyncio

async def deliver_with_refresh(dest, **kw):
    for attempt in range(3):
        try:
            return await dest.deliver(**kw)
        except RuntimeError as e:
            # fresh signed URL on next attempt solves expired/consumed URLs
            if "GCS session init failed" not in str(e) or attempt == 2:
                raise
            await asyncio.sleep(2 ** attempt)

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15). Data as JSON: /api/errors/5d021e11e98e40de. Report an issue: GitHub.