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
- Use `undefined` instead of `null` to remove a header: `{ headers: { 'user-agent': undefined } }`.
- If headers come from JSON/config, strip null entries before passing them to got: `Object.fromEntries(Object.entries(h).filter(([, v]) => v !== null))`.
- 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
- Use `undefined` (or omit the key) to delete a header; never `null`.
- When loading headers from JSON config, drop null entries before the call: `Object.fromEntries(Object.entries(h).filter(([, v]) => v !== null))`.
- Type headers as `Record<string, string | undefined>` to make null impossible at the type level.
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
- Missing `url` property
- The `${key}` header must be a single value
- HTTP/2 pseudo-headers are not supported in `options.headers`
- No URL protocol specified
- The `${options.method}` method cannot be used with a body
AI-assisted analysis of sindresorhus/got@e3924aa1e5 (2026-08-03).
Data as JSON: /data/errors/58c4215455a02df9.json.
Report an issue: GitHub.