can1357/oh-my-pi · error
Gemini Files API upload finalization request failed
Error message
Gemini Files API upload finalization request failed
What it means
The second fetch — POST of the actual bytes to the X-Goog-Upload-URL with 'upload, finalize' — threw at the network level, so the original cause is replaced by this message. The file bytes failed to reach Google (or the connection dropped mid-transfer); HTTP error statuses produce a different message.
Source
Thrown at packages/coding-agent/src/blob-broker/provider-files-gemini.ts:132
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}`);
}
const file = parseFinalizedFile(await responseJson(finalizeResponse, "finalize"));
return {
provider: "google",
id: file.name,
uri: file.uri,
mimeType: file.mimeType,
bytes: byteLength,
expiresAt: file.expiresAt,
delete: {
method: "DELETE",
url: `${GEMINI_FILES_RESOURCE_URL}/${file.name}`,
headers: { "x-goog-api-key": credential },
},View on GitHub (pinned to 9690622007)
Solutions
- Retry the whole upload with backoff — resumable sessions may have expired, so re-run start + finalize.
- Check whether your AbortSignal fired (user cancel or your own timeout).
- Reduce file size or improve connection stability; check proxy body-size/timeout limits.
- For flaky networks, implement chunked resumable uploads yourself using the X-Goog-Upload-Offset protocol instead of single-shot finalize.
- Note the underlying error is swallowed; wrap fetchImpl to log the native cause.
Example fix
// before: single-shot, no retry
const handle = await client.upload({ bytes, mimeType });
// after: retry whole resumable flow on network failure
async function uploadWithRetry(req, attempts = 3) {
try { return await client.upload(req); }
catch (e) {
if (attempts > 1 && String(e.message).includes("finalization request failed")) {
await Bun.sleep(2000);
return uploadWithRetry(req, attempts - 1);
}
throw e;
}
} Defensive patterns
Strategy: retry
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("finalization request failed")) {
if (request.signal?.aborted) throw error;
// network drop mid-body: restart the full resumable flow with backoff
return uploadWithBackoff(request);
} else throw error;
} Prevention
- Retry the entire start+finalize flow — the session URL cannot be safely resumed mid-body without offset bookkeeping
- Distinguish AbortSignal cancellations from network errors before retrying
- Split very large files or use chunked resumable uploads on unstable networks
- Set proxy timeouts/size limits above your largest expected upload
- Wrap fetchImpl to log the swallowed native error for diagnosis
When it happens
Trigger: fetchImpl() on the finalize request rejects: connection reset mid-upload (common with large bodies), request.signal aborted, TLS failure, DNS drop between the two requests, or body streaming failure.
Common situations: Uploading large files over unstable connections; timeouts/proxies killing long POSTs; user cancellation via AbortSignal; Wi-Fi/network switch during upload; request body exceeding an intermediary's size limit.
Related errors
- Gemini Files API upload initialization request failed
- timed out: {command}
- AnthropicConnectionError
- AnthropicConnectionTimeoutError
- xAI device-code request failed: ${error instanceof Error ? e
AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31).
Data as JSON: /api/errors/ac393cf1c7eb3814.
Report an issue: GitHub.