{"record":{"id":"a0641d56556842cd","repo":"trpc/trpc","slug":"bad-request","errorCode":"BAD_REQUEST","errorMessage":"Invalid URL","messagePattern":"Invalid URL","errorType":"error_code","errorClass":"TRPCError","httpStatus":400,"severity":"error","filePath":"packages/server/src/adapters/node-http/incomingMessageToRequest.ts","lineNumber":88,"sourceCode":"    },\n  });\n}\nexport function createURL(req: NodeHTTPRequest): URL {\n  try {\n    const protocol =\n      // http2\n      (req.headers[':scheme'] && req.headers[':scheme'] === 'https') ||\n      // http1\n      (req.socket && 'encrypted' in req.socket && req.socket.encrypted)\n        ? 'https:'\n        : 'http:';\n\n    const host = req.headers.host ?? req.headers[':authority'] ?? 'localhost';\n\n    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n    return new URL(req.url!, `${protocol}//${host}`);\n  } catch (cause) {\n    throw new TRPCError({\n      code: 'BAD_REQUEST',\n      message: 'Invalid URL',\n      cause,\n    });\n  }\n}\n\nfunction createHeaders(incoming: http.IncomingHttpHeaders): Headers {\n  const headers = new Headers();\n\n  for (const key in incoming) {\n    const value = incoming[key];\n    if (typeof key === 'string' && key.startsWith(':')) {\n      // Skip HTTP/2 pseudo-headers\n      continue;\n    }\n\n    if (Array.isArray(value)) {","sourceCodeStart":70,"sourceCodeEnd":106,"githubUrl":"https://github.com/trpc/trpc/blob/acff82332de8b4562d3e6975fa8d94ab1a6de5e0/packages/server/src/adapters/node-http/incomingMessageToRequest.ts#L70-L106","documentation":"`createURL` builds a WHATWG `URL` from the Node `IncomingMessage`'s `req.url` plus a derived protocol and the `Host`/`:authority` header. If `new URL()` rejects (malformed request-target, or a Host header containing illegal characters), the adapter wraps the underlying failure as BAD_REQUEST. This reflects a malformed inbound request or a misbehaving upstream rather than application logic.","triggerScenarios":"A client sends a request line with an invalid request-target; a proxy injects a Host header with spaces, angle brackets, or a malformed port; HTTP/2 with a malformed `:authority` pseudo-header; an absolute-form request URI that is itself invalid.","commonSituations":"Misconfigured reverse proxy or load balancer rewriting the Host header; raw telnet/curl with a broken request line; security scanners/fuzzers sending junk Host values; a custom client omitting or mangling the Host header.","solutions":["Inspect the inbound `Host`/`:authority` header and the request line for illegal characters and fix the origin.","Normalize or reject malformed Host headers at the reverse proxy/edge before they reach tRPC.","Reproduce with a known-good request (e.g. `curl --resolve`) to confirm the server itself is healthy."],"exampleFix":null,"handlingStrategy":"validation","validationCode":"// Normalize/validate the Host header before it reaches tRPC\nfunction safeHost(h: string | undefined): string {\n  if (!h || /[\\s<>]/.test(h)) return 'localhost';\n  return h;\n}","typeGuard":"function isValidHostHeader(host: unknown): host is string {\n  return typeof host === 'string' && host.length > 0 && !/[\\s<>\"{}|\\\\^`]/.test(host);\n}","tryCatchPattern":"try {\n  await nodeHTTPRequestHandler(opts);\n} catch (e) {\n  if (e instanceof TRPCError && e.code === 'BAD_REQUEST' && e.message === 'Invalid URL') {\n    // Log req.headers.host + req.url to find the malformed inbound request\n  }\n  throw e;\n}","preventionTips":["Normalize the Host header at the reverse proxy/edge.","Reject requests with obviously malformed request lines early.","Log the raw Host and request-target when this fires to locate the bad upstream."],"tags":["network","http","request-parsing","node-http"],"backgroundTag":null,"analyzedSha":"acff82332de8b4562d3e6975fa8d94ab1a6de5e0","analyzedAt":"2026-08-12T22:04:41.179Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}