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

  1. Verify the Google API credential has the required scopes and that 'Generative Language API' is enabled in the Google Cloud project.
  2. Retry — a missing upload URL is frequently transient on Google's side.
  3. 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.
  4. 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

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


AI-assisted analysis of n8n-io/n8n@5ac6606e81 (2026-08-12). Data as JSON: /api/errors/5a44cfc44aad93df. Report an issue: GitHub.