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
- 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.
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
- 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.
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
- Mavvrik FOCUS destination: {label} must be HTTPS, got scheme
- Mavvrik FOCUS destination: failed to get signed URL ({resp.s
- Mavvrik FOCUS destination: GCS session init missing Location
- GCS upload failed: status={response.status_code} body={respo
- Mavvrik FOCUS destination: {label} must be a GCS endpoint (s
AI-assisted analysis of BerriAI/litellm@6c2dcb801b (2026-08-15).
Data as JSON: /api/errors/5d021e11e98e40de.
Report an issue: GitHub.