can1357/oh-my-pi · error
Gemini Files API upload initialization response is missing X
Error message
Gemini Files API upload initialization response is missing X-Goog-Upload-URL
What it means
The start request succeeded (2xx) but the response is missing the X-Goog-Upload-URL header, which carries the resumable session URL the client must POST the bytes to. Without it the upload cannot proceed, so the client fails explicitly rather than POSTing to undefined.
Source
Thrown at packages/coding-agent/src/blob-broker/provider-files-gemini.ts:117
"X-Goog-Upload-Command": "start",
"X-Goog-Upload-Header-Content-Length": String(byteLength),
"X-Goog-Upload-Header-Content-Type": request.mimeType,
"X-Goog-Upload-Protocol": "resumable",
"x-goog-api-key": credential,
},
body: JSON.stringify(request.filename ? { file: { display_name: request.filename } } : { file: {} }),
signal: request.signal,
});
} catch {
throw new Error("Gemini Files API upload initialization request failed");
}
if (!startResponse.ok) {
throw new Error(`Gemini Files API upload initialization failed with HTTP ${startResponse.status}`);
}
const uploadUrl = startResponse.headers.get("X-Goog-Upload-URL")?.trim();
if (!uploadUrl)
throw new Error("Gemini Files API upload initialization response is missing X-Goog-Upload-URL");
let finalizeResponse: Response;
try {
finalizeResponse = await fetchImpl(uploadUrl, {
method: "POST",
headers: {
"Content-Length": String(byteLength),
"X-Goog-Upload-Command": "upload, finalize",
"X-Goog-Upload-Offset": "0",
},
body: request.bytes,
signal: request.signal,
});
} catch {
throw new Error("Gemini Files API upload finalization request failed");
}
if (!finalizeResponse.ok) {
throw new Error(`Gemini Files API upload finalization failed with HTTP ${finalizeResponse.status}`);View on GitHub (pinned to 9690622007)
Solutions
- Check for proxies/gateways that strip X-Goog-* response headers and whitelist them.
- Verify your fetch implementation preserves header case (Headers are case-insensitive per spec; polyfills may not be).
- Log all response headers via a debug FetchImpl wrapper to see what Google actually returned.
- Retry — a transient Google-side anomaly can produce a 2xx without the session URL.
- Check Google's status dashboard / release notes for Files API changes.
Example fix
// before: opaque failure
await client.upload(request);
// after: log headers to diagnose
const debugFetch: FetchImpl = async (url, init) => {
const res = await fetch(url, init);
if (!res.headers.get("x-goog-upload-url")) console.error("start headers:", [...res.headers]);
return res;
}; Defensive patterns
Strategy: fallback
Validate before calling
null
Type guard
null
Try / catch
try {
const handle = await client.upload(request);
} catch (error) {
if (error instanceof Error && error.message.includes("X-Goog-Upload-URL")) {
// header stripped or API drift: fall back to base64-inline attachment or retry once
return inlineAttachmentFallback(request);
} else throw error;
} Prevention
- Whitelist X-Goog-* response headers on proxies/gateways for API hosts
- Use spec-compliant fetch (Headers are case-insensitive); avoid leaky polyfills
- Log full response headers when diagnosing upload issues
- Keep a non-Files-API upload fallback path in your integration
When it happens
Trigger: startResponse.ok is true but headers.get("X-Goog-Upload-URL") is null or blank — Google returned an unexpected 2xx body/header set, or an intermediary stripped the custom header.
Common situations: Proxy or gateway stripping non-standard X-Goog-* response headers; a Google API behavior change; a fetch implementation that drops/case-mangles header names (custom FetchImpl or polyfill); Google incident returning 200 with an error body.
Related errors
- Gemini Files API finalized file state is not ACTIVE
- Gemini Files API upload initialization failed with HTTP ${st
- Anthropic file upload returned an invalid expiration time
- Gemini Files API ${context} response is not valid JSON
- Gemini Files API finalize response is missing ${field}
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/45a63895537b42de.
Report an issue: GitHub.