trpc/trpc · error · TRPCError

BAD_REQUEST

BAD_REQUEST

Error message

Invalid URL

What it means

`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.

Source

Thrown at packages/server/src/adapters/node-http/incomingMessageToRequest.ts:88

    },
  });
}
export function createURL(req: NodeHTTPRequest): URL {
  try {
    const protocol =
      // http2
      (req.headers[':scheme'] && req.headers[':scheme'] === 'https') ||
      // http1
      (req.socket && 'encrypted' in req.socket && req.socket.encrypted)
        ? 'https:'
        : 'http:';

    const host = req.headers.host ?? req.headers[':authority'] ?? 'localhost';

    // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
    return new URL(req.url!, `${protocol}//${host}`);
  } catch (cause) {
    throw new TRPCError({
      code: 'BAD_REQUEST',
      message: 'Invalid URL',
      cause,
    });
  }
}

function createHeaders(incoming: http.IncomingHttpHeaders): Headers {
  const headers = new Headers();

  for (const key in incoming) {
    const value = incoming[key];
    if (typeof key === 'string' && key.startsWith(':')) {
      // Skip HTTP/2 pseudo-headers
      continue;
    }

    if (Array.isArray(value)) {

View on GitHub (pinned to acff82332d)

Solutions

  1. Inspect the inbound `Host`/`:authority` header and the request line for illegal characters and fix the origin.
  2. Normalize or reject malformed Host headers at the reverse proxy/edge before they reach tRPC.
  3. Reproduce with a known-good request (e.g. `curl --resolve`) to confirm the server itself is healthy.
Defensive patterns

Strategy: validation

Validate before calling

// Normalize/validate the Host header before it reaches tRPC
function safeHost(h: string | undefined): string {
  if (!h || /[\s<>]/.test(h)) return 'localhost';
  return h;
}

Type guard

function isValidHostHeader(host: unknown): host is string {
  return typeof host === 'string' && host.length > 0 && !/[\s<>"{}|\\^`]/.test(host);
}

Try / catch

try {
  await nodeHTTPRequestHandler(opts);
} catch (e) {
  if (e instanceof TRPCError && e.code === 'BAD_REQUEST' && e.message === 'Invalid URL') {
    // Log req.headers.host + req.url to find the malformed inbound request
  }
  throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of trpc/trpc@acff82332d (2026-08-12). Data as JSON: /api/errors/a0641d56556842cd. Report an issue: GitHub.