{"id":"2cf40f991ee9ac48","repo":"sindresorhus/got","slug":"http-2-pseudo-headers-are-not-supported-in-option","errorCode":null,"errorMessage":"HTTP/2 pseudo-headers are not supported in `options.headers`: ${name}","messagePattern":"HTTP/2 pseudo-headers are not supported in `options\\.headers`: (.+?)","errorType":"validation","errorClass":"TypeError","httpStatus":null,"severity":"error","filePath":"source/core/options.ts","lineNumber":1125,"sourceCode":"\t\t} finally {\n\t\t\toptions.allowAbsoluteUrls = allowAbsoluteUrls;\n\t\t}\n\t}\n\n\tif (username !== undefined) {\n\t\toptions.username = username;\n\t}\n\n\tif (password !== undefined) {\n\t\toptions.password = password;\n\t}\n\n\treturn options.url as URL;\n}\n\nfunction assertValidHeaderName(name: string): void {\n\tif (name.startsWith(':')) {\n\t\tthrow new TypeError(`HTTP/2 pseudo-headers are not supported in \\`options.headers\\`: ${name}`);\n\t}\n}\n\n/**\nSafely assign own properties from source to target, skipping `__proto__` to prevent prototype pollution from JSON.parse'd input.\n*/\nfunction safeObjectAssign<Target extends Record<string, unknown>, Source extends Record<string, unknown>>(target: Target, source: Source): void {\n\tfor (const [key, value] of Object.entries(source)) {\n\t\tif (key === '__proto__') {\n\t\t\tcontinue;\n\t\t}\n\n\t\tReflect.set(target, key, value);\n\t}\n}\n\nconst isToughCookieJar = (cookieJar: PromiseCookieJar | ToughCookieJar): cookieJar is ToughCookieJar => cookieJar.setCookie.length === 4 && cookieJar.getCookieString.length === 0;\n","sourceCodeStart":1107,"sourceCodeEnd":1143,"githubUrl":"https://github.com/sindresorhus/got/blob/e3924aa1e53a6ca3eb93a43618ce532442a89b40/source/core/options.ts#L1107-L1143","documentation":"Thrown at source/core/options.ts:1125 by `assertValidHeaderName`. HTTP/2 reserves header names starting with `:` (pseudo-headers like `:method`, `:path`, `:authority`, `:scheme`) — these are derived automatically by the HTTP/2 layer and must not be set by the user. The check rejects any header name beginning with `:` regardless of HTTP version, because passing such a header would either be silently dropped (HTTP/1) or conflict with the protocol's own pseudo-headers (HTTP/2).","triggerScenarios":"Passing `headers: { ':authority': 'x' }`, `headers: { ':method': 'GET' }`, or any header key starting with a colon; programmatically building headers from a map that includes pseudo-headers; copy-pasting HTTP/2 traces into request code.","commonSituations":"Migrating from gRPC/HTTP2 debug traces into a got client; building headers from a generic serializer that includes pseudo-headers; tooling that surfaces `:path` as if it were a regular header.","solutions":["Remove pseudo-headers (`:method`, `:path`, `:scheme`, `:authority`) from your headers object — they are set by the protocol.","For the equivalent control in HTTP/1, use the corresponding options: `method`, `url`/`path`, and the `host` header.","Filter incoming header maps before passing them: `Object.fromEntries(Object.entries(h).filter(([k]) => !k.startsWith(':')))`."],"exampleFix":"// before\nawait got(url, { headers: { ':authority': 'api.example.com', 'user-agent': 'x' } });\n\n// after — use regular headers only\nawait got(url, { headers: { host: 'api.example.com', 'user-agent': 'x' } });\n\n// filter pseudo-headers from upstream source\nconst headers = Object.fromEntries(\n  Object.entries(rawHeaders).filter(([k]) => !k.startsWith(':'))\n);","handlingStrategy":"validation","validationCode":"function stripPseudoHeaders(headers) {\n  for (const key of Object.keys(headers)) {\n    if (key.startsWith(':')) {\n      throw new TypeError(`HTTP/2 pseudo-headers are not supported in options.headers: ${key}`);\n    }\n  }\n  return headers;\n}\nawait got(url, { headers: stripPseudoHeaders(headers) });","typeGuard":"function hasPseudoHeader(headers: Record<string, unknown>): boolean {\n  return Object.keys(headers).some(k => k.startsWith(':'));\n}","tryCatchPattern":"try {\n  await got(url, { headers });\n} catch (error) {\n  if (error instanceof TypeError && /HTTP\\/2 pseudo-headers are not supported/.test(error.message)) {\n    const cleaned = Object.fromEntries(Object.entries(headers).filter(([k]) => !k.startsWith(':')));\n    return got(url, { headers: cleaned });\n  }\n  throw error;\n}","preventionTips":["Never include headers whose name starts with ':' — pseudo-headers are set by the HTTP/2 layer.","Filter incoming header maps (e.g. from HTTP/2 traces or gRPC) before passing to got.","Use `method`, `url`, and the `host` header instead of :method/:path/:authority."],"tags":["headers","http2","pseudo-headers","validation"],"analyzedSha":"e3924aa1e53a6ca3eb93a43618ce532442a89b40","analyzedAt":"2026-08-03T19:22:24.770Z","schemaVersion":2}