n8n-io/n8n · error · NodeOperationError
Failed to get upload URL
Error message
Failed to get upload URL
What it means
Failure in uploadStream's resumable-upload init: after POSTing to the endpoint with X-Goog-Upload-Protocol: resumable / Command: start, Google is expected to return an 'x-goog-upload-url' response header. If that header is absent, the node cannot proceed to the byte-upload phase and throws this bare message (no description attached).
Source
Thrown at packages/@n8n/nodes-langchain/nodes/vendors/GoogleGemini/helpers/utils.ts:193
stream: Stream,
config: UploadStreamConfig,
): Promise<{ body: IDataObject }> {
const { endpoint, mimeType, body } = config;
const uploadInitResponse = (await apiRequest.call(this, 'POST', endpoint, {
headers: {
'X-Goog-Upload-Protocol': 'resumable',
'X-Goog-Upload-Command': 'start',
'X-Goog-Upload-Header-Content-Type': mimeType,
'Content-Type': 'application/json',
},
body,
option: { returnFullResponse: true },
})) as { headers: IDataObject };
const uploadUrl = uploadInitResponse.headers['x-goog-upload-url'] as string;
if (!uploadUrl) {
throw new NodeOperationError(this.getNode(), 'Failed to get upload URL');
}
return (await this.helpers.httpRequest({
method: 'POST',
url: uploadUrl,
headers: {
'X-Goog-Upload-Offset': '0',
'X-Goog-Upload-Command': 'upload, finalize',
'Content-Type': mimeType,
},
body: stream,
returnFullResponse: true,
})) as { body: IDataObject };
}
export async function transferFile(
this: IExecuteFunctions,
i: number,View on GitHub (pinned to 5ac6606e81)
Solutions
- Verify the Google API credential has the required scopes and that 'Generative Language API' is enabled in the Google Cloud project.
- Retry — a missing upload URL is frequently transient on Google's side.
- Check the apiRequest call earlier didn't silently swallow a non-2xx; if you can, capture the start response status/body to see Google's reason.
- Confirm mimeType is a non-empty, valid MIME string before this call.
Defensive patterns
Strategy: retry
Type guard
function hasUploadUrl(headers: Record<string, unknown>): boolean {
return typeof headers['x-goog-upload-url'] === 'string' && (headers['x-goog-upload-url'] as string).length > 0;
} Try / catch
for (let attempt = 1; attempt <= 3; attempt++) {
try { return await uploadStream(stream, config); }
catch (e) {
if (attempt === 3 || !/upload url/i.test(e.message)) throw e;
await new Promise(r => setTimeout(r, 1000 * attempt));
}
} Prevention
- Ensure the credential has the Generative Language / Cloud Platform scope before relying on resumable uploads.
- Confirm mimeType is a non-empty, valid MIME string — empty mimeType can make Google refuse the start command.
- Retry on a missing upload URL — it's frequently transient.
When it happens
Trigger: Google's resumable-upload start endpoint responded without issuing an upload URL — typically a 4xx/5xx that wasn't surfaced as a thrown HTTP error earlier (e.g. auth still valid enough to get a 200 with an error body), or a region/project where the Files API is unavailable, or a malformed body/mimeType.
Common situations: API key / OAuth scope lacks the cloudplatform or generativelanguage scope; the project hasn't enabled the Generative Language API; transient Google-side issue; mimeType header empty causing Google to refuse the start.
Related errors
- ${uploadResponse.file.error?.message ?? 'Unknown error'}
- ${file.error?.message ?? 'Unknown error'}
- ${response.error.message}
- Binary property name or download URL is required
- ${operation.error.message ?? 'Unknown error'}
AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12).
Data as JSON: /api/errors/5a44cfc44aad93df.
Report an issue: GitHub.