Skip to content

files.upload sets a redundant Content-Length that breaks uploads under a userland undici dispatcher #1718

Description

@elierotenberg

This is a client library issue.

The SDK sets a duplicate Content-Length header in files.upload().

Environment details

  • Programming language: TypeScript / JavaScript
  • OS: Linux (any OS running Node)
  • Language runtime version: Node.js 24.15.0
  • Bundled undici version for Node.js 24.15.0: 7.24.4 (relevant to this issue, please see below)
  • Direct dependency undici installed version: 7.28 (relevant to this issue, please see below)
  • Package version: @google/genai 2.8.0

Steps to reproduce

  1. Import undici (version >= 7.26) and set a global dispatcher.
  2. Call files.upload(...). It fails with InvalidArgumentError: invalid content-length header (UND_ERR_INVALID_ARG).

Minimal repro (not GenAI SDK specific, illustrating the problem):

import { Agent } from 'undici'; // >= 7.26
const body = new Blob([new Uint8Array(8)]);
await fetch('http://localhost', {
  method: 'POST', body,
  headers: { 'Content-Length': String(body.size) },
  dispatcher: new Agent(),
});

SDK repro (needs an API key):

import { GoogleGenAI } from '@google/genai';
import { setGlobalDispatcher, Agent } from 'undici'; // >= 7.26

setGlobalDispatcher(new Agent());

const ai = new GoogleGenAI({ apiKey: process.env.GEMINI_API_KEY });
await ai.files.upload({
  file: new Blob([new Uint8Array(1024)], { type: 'text/plain' }),
  config: { mimeType: 'text/plain' },
});
// InvalidArgumentError: invalid content-length header (UND_ERR_INVALID_ARG)

Concrete use case

I'm importing undici elsewhere in my code, which immediately sets a global dispatcher if loaded before NodeJS bundled undici (depending on module load order).

Please note that at the time of writing, Node 24 bundles undici@7.24.4 which predates the strict validator. I expect the issue to affect all SDK users when Node bundled version is updated to >=7.26.

Suspected cause

files.upload sets Content-Length manually on each chunk (_node_uploader.ts#L286, _cross_uploader.ts#L146).

Undici fetch also derives it from the body, so the request has it twice, which undici >= 7.26 rejects.

Possible fix

While it is debatable whether undici should be this aggressively strict, skipping setting Content-Length explicitly and letting fetch derive it automatically fixes the problem.

I have created a patch locally which does exactly that, and I'm happy to open a PR if you want!

Metadata

Metadata

Assignees

Labels

api:gemini-apipriority: p2Moderately-important priority. Fix may not be included in next release.type: bugError or flaw in code with unintended results or allowing sub-optimal usage patterns.

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions