{"record":{"id":"e2bb67770d6a6de1","repo":"musistudio/claude-code-router","slug":"proxy-request-is-missing-host-header","errorCode":null,"errorMessage":"Proxy request is missing Host header.","messagePattern":"Proxy request is missing Host header\\.","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core/src/proxy/service.ts","lineNumber":1346,"sourceCode":"    return normalizedHost.endsWith(normalizedPattern);\n  }\n  return false;\n}\n\nfunction buildGatewayUrl(config: AppConfig, targetUrl: URL): URL {\n  const gatewayHost = config.gateway.host === \"0.0.0.0\" ? \"127.0.0.1\" : config.gateway.host;\n  return new URL(`${targetUrl.pathname}${targetUrl.search}`, `http://${gatewayHost}:${config.gateway.port}`);\n}\n\nfunction resolveRequestUrl(request: IncomingMessage, defaultProtocol: \"http:\" | \"https:\"): URL {\n  const rawUrl = request.url || \"/\";\n  if (/^https?:\\/\\//i.test(rawUrl)) {\n    return new URL(rawUrl);\n  }\n\n  const host = readHeader(request.headers.host);\n  if (!host) {\n    throw new Error(\"Proxy request is missing Host header.\");\n  }\n  return new URL(`${defaultProtocol}//${host}${rawUrl.startsWith(\"/\") ? rawUrl : `/${rawUrl}`}`);\n}\n\nfunction parseConnectTarget(value: string | undefined): { hostname: string; port: number } {\n  if (!value) {\n    throw new Error(\"CONNECT target is missing.\");\n  }\n  const parsed = new URL(`http://${value}`);\n  return {\n    hostname: parsed.hostname,\n    port: parsed.port ? Number(parsed.port) : 443\n  };\n}\n\nfunction proxyEndpoint(config: AppConfig): string {\n  const host = config.proxy.host === \"0.0.0.0\" ? \"127.0.0.1\" : config.proxy.host;\n  return `http://${host}:${config.proxy.port}`;","sourceCodeStart":1328,"sourceCodeEnd":1364,"githubUrl":"https://github.com/musistudio/claude-code-router/blob/99f24806c6a2c660b16e53e95211c517448a6c90/packages/core/src/proxy/service.ts#L1328-L1364","documentation":"An HTTP proxy request arrived with a relative URL (path-only form) and no Host header, so the proxy cannot reconstruct the absolute target URL. Proxy-style requests require either an absolute URL or an origin-form path plus a Host header.","triggerScenarios":"Calling the proxy with a plain HTTP request whose request-line is origin-form (e.g. GET /path) and whose headers lack Host — e.g. hand-rolled Node http.request through the proxy without setting host, or a client that strips Host.","commonSituations":"Custom test clients using http.request({path: \"/x\"}) without host; proxying HTTP/1.0-style requests that omit Host; middleware that deletes the host header; malformed curl invocations (-H 'Host:').","solutions":["Send the absolute URL in the request-line (proxy form: GET http://host/path HTTP/1.1)","Otherwise set a valid Host header on the request before it reaches the proxy","If writing a custom client, use a proper proxy-aware agent (e.g. http-proxy-agent) instead of raw sockets"],"exampleFix":"// before\nhttp.request({ host: \"127.0.0.1\", port: proxyPort, path: \"/api/v1\" }); // throws\n\n// after\nhttp.request({ host: \"127.0.0.1\", port: proxyPort, path: \"http://example.com/api/v1\", headers: { host: \"example.com\" } });","handlingStrategy":"validation","validationCode":"const url = rawUrl.startsWith(\"http\") ? rawUrl : `http://${headers.host}${rawUrl}`;\nif (!headers.host && !/^https?:\\/\\//i.test(rawUrl)) {\n  return badRequest();\n}\nawait proxyRequest(rawUrl, headers);","typeGuard":"function hasValidProxyTarget(rawUrl: string, headers: IncomingHttpHeaders): boolean {\n  return /^https?:\\/\\//i.test(rawUrl) || typeof headers.host === \"string\" && headers.host.length > 0;\n}","tryCatchPattern":"try { await handleProxyRequest(req); } catch (e) { if (e.message.includes(\"missing Host header\")) return respond(400, \"Host header required\"); throw e; }","preventionTips":["Use standard proxy-aware agents instead of raw requests","Always set absolute URLs or Host when crafting proxy requests","Validate requests at the edge before forwarding"],"tags":["proxy","http","host-header","request-parsing"],"backgroundTag":"missing-host-header","analyzedSha":"99f24806c6a2c660b16e53e95211c517448a6c90","analyzedAt":"2026-08-27T04:11:01.184Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}