n8n-io/n8n · error · NodeOperationError

${file.error?.message ?? 'Unknown error'}

Error message

${file.error?.message ?? 'Unknown error'}

What it means

Streamed-upload counterpart of [848]. In transferFile, after uploadStream finishes and the code polls the File until ACTIVE/FAILED, a FAILED state throws file.error?.message ?? 'Unknown error' with description 'Error uploading file'. Same semantic as the buffer path but reached via the streaming transferFile helper.

Source

Thrown at packages/@n8n/nodes-langchain/nodes/vendors/GoogleGemini/helpers/utils.ts:242

	if ('buffer' in fileData) {
		return await uploadFile.call(this, fileData.buffer, fileData.mimeType);
	}

	const { stream, mimeType } = fileData;
	const uploadResponse = (await uploadStream.call(this, stream, {
		endpoint: '/upload/v1beta/files',
		mimeType,
	})) as { body: { file: File } };

	let file = uploadResponse.body.file;

	while (file.state !== 'ACTIVE' && file.state !== 'FAILED') {
		await new Promise((resolve) => setTimeout(resolve, OPERATION_CHECK_INTERVAL));
		file = (await apiRequest.call(this, 'GET', `/v1beta/${file.name}`)) as File;
	}

	if (file.state === 'FAILED') {
		throw new NodeOperationError(this.getNode(), file.error?.message ?? 'Unknown error', {
			description: 'Error uploading file',
		});
	}

	return { fileUri: file.uri, mimeType: file.mimeType };
}

export async function createFileSearchStore(this: IExecuteFunctions, displayName: string) {
	return (await apiRequest.call(this, 'POST', '/v1beta/fileSearchStores', {
		body: { displayName },
	})) as IDataObject;
}

export async function uploadToFileSearchStore(
	this: IExecuteFunctions,
	i: number,
	fileSearchStoreName: string,
	displayName: string,

View on GitHub (pinned to 5ac6606e81)

Solutions

  1. Read file.error.message — it carries Google's reason for the FAILED state.
  2. Re-encode the source to a supported MIME; reduce size; retry on transient errors.
  3. If downloading from a URL, first fetch and validate the content-type matches a Gemini-supported type before transferFile.
Defensive patterns

Strategy: retry

Validate before calling

function isSupportedForUpload(contentType: string | undefined): boolean {
  const SUPPORTED = ['application/pdf','image/png','image/jpeg','image/webp','audio/mpeg','audio/wav','video/mp4'];
  return !!contentType && SUPPORTED.includes(contentType.split(';')[0]);
}

Type guard

function isStreamableUploadFailure(file: { state: string; error?: { message: string } }): boolean {
  return file.state === 'FAILED';
}

Try / catch

for (let attempt = 1; attempt <= 3; attempt++) {
  try { return await transferFile(i, url, mime); }
  catch (e) {
    if (attempt === 3 || /unsupported|too large/i.test(e.message)) throw e;
    await new Promise(r => setTimeout(r, 1000 * attempt));
  }
}

Prevention

When it happens

Trigger: transferFile is used (URL or binary-as-stream source) and Google reports the uploaded file's state as FAILED — same causes as [848]: unsupported type, too large, safety rejection, or backend error.

Common situations: Downloading a remote file (HTTP Request → URL) and piping it straight to Gemini where the format is rejected; streaming a large media file that exceeds tier limits.

Related errors


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