sindresorhus/got · error · TypeError

Use `undefined` instead of `null` to delete the `${key}` hea

Error message

Use `undefined` instead of `null` to delete the `${key}` header

What it means

Thrown at source/core/index.ts:2185 inside `sanitizeHeaders`. got's header model uses `undefined` to signal 'delete this header' and treats `null` values as a mistake. The check fires whenever a header value is strictly null: the library refuses to guess whether the user meant 'remove the header' (use undefined) or 'send the literal string null'. Requiring undefined keeps the contract unambiguous and matches the underlying Node http behavior where undefined omits the header.

Source

Thrown at source/core/index.ts:2185

				options.setInternalHeader(name, nextHeader);
			} else if (!is.undefined(explicitHeader) && currentHeader === staleGeneratedHeader) {
				options.setInternalHeader(name, explicitHeader);
			} else if (shouldDeleteGeneratedHeader(currentHeader, staleGeneratedHeader)) {
				options.deleteInternalHeader(name);
			}
		};

		const getAuthorizationHeader = (username: string, password: string, isExplicitlyOmitted: boolean) => !isExplicitlyOmitted && (username || password)
			? `Basic ${stringToBase64(`${username}:${password}`)}`
			: undefined;
		const sanitizeHeaders = () => {
			const currentHeaders = options.getInternalHeaders();

			for (const key in currentHeaders) {
				if (is.undefined(currentHeaders[key])) {
					options.deleteInternalHeader(key);
				} else if (is.null(currentHeaders[key])) {
					throw new TypeError(`Use \`undefined\` instead of \`null\` to delete the \`${key}\` header`);
				} else if (Array.isArray(currentHeaders[key]) && key === 'transfer-encoding') {
					// Node serializes request header arrays as repeated field lines. Keep framing
					// unambiguous by allowing only one transfer-encoding value here.
					if (currentHeaders[key].length !== 1) {
						throw new TypeError(`The \`${key}\` header must be a single value`);
					}

					options.setInternalHeader(key, currentHeaders[key][0]);
				} else if (Array.isArray(currentHeaders[key]) && singleValueRequestHeaders.has(key)) {
					// Duplicate credential and content-length lines are not allowed on requests.
					// Normalize a single-element array to match the long-supported string path.
					if (currentHeaders[key].length !== 1) {
						throw new TypeError(`The \`${key}\` header must be a single value`);
					}

					options.setInternalHeader(key, currentHeaders[key][0]);
				}
			}

View on GitHub (pinned to e3924aa1e5)

Solutions

  1. Use `undefined` instead of `null` to remove a header: `{ headers: { 'user-agent': undefined } }`.
  2. If headers come from JSON/config, strip null entries before passing them to got: `Object.fromEntries(Object.entries(h).filter(([, v]) => v !== null))`.
  3. Delete the key from the object entirely — `{ 'user-agent': undefined }` and omitting the key are equivalent to got.

Example fix

// before
await got(url, { headers: { 'user-agent': null, accept: '*/*' } });

// after — use undefined (or omit the key)
await got(url, { headers: { 'user-agent': undefined, accept: '*/*' } });

// sanitize headers loaded from JSON
const headers = JSON.parse(config).headers;
for (const k of Object.keys(headers)) if (headers[k] === null) delete headers[k];
Defensive patterns

Strategy: validation

Validate before calling

// Strip nulls from header objects before passing to got.
function sanitizeHeaders(headers) {
  const out = {};
  for (const [k, v] of Object.entries(headers)) {
    if (v === null) continue;          // drop null entries (use undefined semantics)
    out[k] = v === undefined ? undefined : v;
  }
  return out;
}
await got(url, { headers: sanitizeHeaders(rawHeaders) });

Type guard

function hasNullHeader(headers: Record<string, unknown>): boolean {
  return Object.values(headers).some(v => v === null);
}

Try / catch

try {
  await got(url, { headers });
} catch (error) {
  if (error instanceof TypeError && /Use `undefined` instead of `null`/.test(error.message)) {
    // rewrite and retry
    const cleaned = Object.fromEntries(Object.entries(headers).map(([k, v]) => [k, v === null ? undefined : v]));
    return got(url, { headers: cleaned });
  }
  throw error;
}

Prevention

When it happens

Trigger: Passing `{ headers: { 'user-agent': null } }` to delete a header; spreading an options object where some header fields are null; JSON config that serializes missing values as null rather than omitting the key.

Common situations: Loading request headers from JSON config (JSON has no undefined, so optional fields become null); spreading merged options where a later merge sets a header to null intending to clear it; copy-pasting from code samples that use null.

Related errors


AI-assisted analysis of sindresorhus/got@e3924aa1e5 (2026-08-03). Data as JSON: /data/errors/58c4215455a02df9.json. Report an issue: GitHub.