{"id":"58c4215455a02df9","repo":"sindresorhus/got","slug":"use-undefined-instead-of-null-to-delete-the","errorCode":null,"errorMessage":"Use `undefined` instead of `null` to delete the `${key}` header","messagePattern":"Use `undefined` instead of `null` to delete the `(.+?)` header","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"source/core/index.ts","lineNumber":2185,"sourceCode":"\t\t\t\toptions.setInternalHeader(name, nextHeader);\n\t\t\t} else if (!is.undefined(explicitHeader) && currentHeader === staleGeneratedHeader) {\n\t\t\t\toptions.setInternalHeader(name, explicitHeader);\n\t\t\t} else if (shouldDeleteGeneratedHeader(currentHeader, staleGeneratedHeader)) {\n\t\t\t\toptions.deleteInternalHeader(name);\n\t\t\t}\n\t\t};\n\n\t\tconst getAuthorizationHeader = (username: string, password: string, isExplicitlyOmitted: boolean) => !isExplicitlyOmitted && (username || password)\n\t\t\t? `Basic ${stringToBase64(`${username}:${password}`)}`\n\t\t\t: undefined;\n\t\tconst sanitizeHeaders = () => {\n\t\t\tconst currentHeaders = options.getInternalHeaders();\n\n\t\t\tfor (const key in currentHeaders) {\n\t\t\t\tif (is.undefined(currentHeaders[key])) {\n\t\t\t\t\toptions.deleteInternalHeader(key);\n\t\t\t\t} else if (is.null(currentHeaders[key])) {\n\t\t\t\t\tthrow new TypeError(`Use \\`undefined\\` instead of \\`null\\` to delete the \\`${key}\\` header`);\n\t\t\t\t} else if (Array.isArray(currentHeaders[key]) && key === 'transfer-encoding') {\n\t\t\t\t\t// Node serializes request header arrays as repeated field lines. Keep framing\n\t\t\t\t\t// unambiguous by allowing only one transfer-encoding value here.\n\t\t\t\t\tif (currentHeaders[key].length !== 1) {\n\t\t\t\t\t\tthrow new TypeError(`The \\`${key}\\` header must be a single value`);\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.setInternalHeader(key, currentHeaders[key][0]);\n\t\t\t\t} else if (Array.isArray(currentHeaders[key]) && singleValueRequestHeaders.has(key)) {\n\t\t\t\t\t// Duplicate credential and content-length lines are not allowed on requests.\n\t\t\t\t\t// Normalize a single-element array to match the long-supported string path.\n\t\t\t\t\tif (currentHeaders[key].length !== 1) {\n\t\t\t\t\t\tthrow new TypeError(`The \\`${key}\\` header must be a single value`);\n\t\t\t\t\t}\n\n\t\t\t\t\toptions.setInternalHeader(key, currentHeaders[key][0]);\n\t\t\t\t}\n\t\t\t}","sourceCodeStart":2167,"sourceCodeEnd":2203,"githubUrl":"https://github.com/sindresorhus/got/blob/e3924aa1e53a6ca3eb93a43618ce532442a89b40/source/core/index.ts#L2167-L2203","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\nawait got(url, { headers: { 'user-agent': null, accept: '*/*' } });\n\n// after — use undefined (or omit the key)\nawait got(url, { headers: { 'user-agent': undefined, accept: '*/*' } });\n\n// sanitize headers loaded from JSON\nconst headers = JSON.parse(config).headers;\nfor (const k of Object.keys(headers)) if (headers[k] === null) delete headers[k];","handlingStrategy":"validation","validationCode":"// Strip nulls from header objects before passing to got.\nfunction sanitizeHeaders(headers) {\n  const out = {};\n  for (const [k, v] of Object.entries(headers)) {\n    if (v === null) continue;          // drop null entries (use undefined semantics)\n    out[k] = v === undefined ? undefined : v;\n  }\n  return out;\n}\nawait got(url, { headers: sanitizeHeaders(rawHeaders) });","typeGuard":"function hasNullHeader(headers: Record<string, unknown>): boolean {\n  return Object.values(headers).some(v => v === null);\n}","tryCatchPattern":"try {\n  await got(url, { headers });\n} catch (error) {\n  if (error instanceof TypeError && /Use `undefined` instead of `null`/.test(error.message)) {\n    // rewrite and retry\n    const cleaned = Object.fromEntries(Object.entries(headers).map(([k, v]) => [k, v === null ? undefined : v]));\n    return got(url, { headers: cleaned });\n  }\n  throw error;\n}","preventionTips":["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."],"tags":["headers","null-vs-undefined","validation","configuration"],"analyzedSha":"e3924aa1e53a6ca3eb93a43618ce532442a89b40","analyzedAt":"2026-08-03T19:22:24.770Z","schemaVersion":2}