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
- 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.
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
- 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.
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
- FormData is only supported for mutations
- Octet type input is only supported for mutations
- Subscriptions are unsupported by `httpLink` - use `httpSubsc
- BAD_REQUEST
- METHOD_NOT_SUPPORTED
AI-assisted analysis of trpc/trpc@acff82332d (2026-08-12).
Data as JSON: /api/errors/a0641d56556842cd.
Report an issue: GitHub.