{"record":{"id":"405cd4f7ba0d62c6","repo":"angular/angular-cli","slug":"host-value-cannot-be-an-array","errorCode":null,"errorMessage":"host value cannot be an array.","messagePattern":"host value cannot be an array\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/angular/ssr/node/src/request.ts","lineNumber":142,"sourceCode":"    originalUrl,\n  } = nodeRequest as IncomingMessage & { originalUrl?: string };\n\n  const forwardedHeaderValue = getAllowedProxyHeaderValue(headers, 'forwarded', trustProxyHeaders);\n  const forwardedParams = parseForwardedHeader(forwardedHeaderValue);\n\n  const protocol =\n    forwardedParams.proto ??\n    getAllowedProxyHeaderValue(headers, 'x-forwarded-proto', trustProxyHeaders) ??\n    ('encrypted' in socket && socket.encrypted ? 'https' : 'http');\n\n  const hostname =\n    forwardedParams.host ??\n    getAllowedProxyHeaderValue(headers, 'x-forwarded-host', trustProxyHeaders) ??\n    headers.host ??\n    headers[':authority'];\n\n  if (Array.isArray(hostname)) {\n    throw new Error('host value cannot be an array.');\n  }\n\n  let hostnameWithPort = hostname;\n  if (!hostname?.includes(':')) {\n    const port = getAllowedProxyHeaderValue(headers, 'x-forwarded-port', trustProxyHeaders);\n    if (port) {\n      hostnameWithPort += `:${port}`;\n    }\n  }\n\n  return new URL(`${protocol}://${hostnameWithPort}${originalUrl ?? url}`);\n}\n\n/**\n * Gets the first value of an allowed proxy header.\n *\n * @param headers - The Node.js incoming HTTP headers.\n * @param headerName - The name of the proxy header to retrieve.","sourceCodeStart":124,"sourceCodeEnd":160,"githubUrl":"https://github.com/angular/angular-cli/blob/bb72145f9ab45aee29f523236b3a25cd0813a841/packages/angular/ssr/node/src/request.ts#L124-L160","documentation":"When building the request URL from a Node request, the code resolves the hostname from forwarded-host headers, the host header, or HTTP/2 :authority. If the resolved value is an array (duplicate/malformed headers), it throws because a single host string is required.","triggerScenarios":"Node requests where headers.host, x-forwarded-host, or :authority parsed as an array (repeated headers), typically behind misconfigured proxies/load balancers sending the header twice.","commonSituations":"Reverse proxies (nginx/HAProxy) appending rather than setting x-forwarded-host, HTTP/2 with duplicate pseudo-headers, hand-crafted requests with duplicated Host headers.","solutions":["Fix the proxy to overwrite (not append) x-forwarded-host: e.g. nginx `proxy_set_header X-Forwarded-Host $host;`","Deduplicate headers in middleware before handing the request to Angular SSR","Set trustProxyHeaders appropriately so only the intended header is honored","Normalize headers.host to a string in a custom server wrapper before render"],"exampleFix":"// before (nginx appends)\nproxy_set_header X-Forwarded-Host $proxy_add_x_forwarded_host;\n// after (overwrites)\nproxy_set_header X-Forwarded-Host $host;","handlingStrategy":"validation","validationCode":"const host = req.headers['x-forwarded-host'] ?? req.headers.host;\nif (Array.isArray(host)) {\n  console.error('Duplicate host header from proxy; fix upstream before SSR');\n  return new Response('Bad Request', { status: 400 });\n}","typeGuard":"function isSingleHeader(v: string | string[] | undefined): v is string {\n  return typeof v === 'string';\n}","tryCatchPattern":"try {\n  const url = createRequestUrl(req);\n} catch (e) {\n  if (e instanceof Error && e.message.includes('host value cannot be an array')) {\n    return new Response('Bad Request: duplicate host header', { status: 400 });\n  }\n  throw e;\n}","preventionTips":["Configure proxies to overwrite, not append, Host/X-Forwarded-Host headers","Add middleware that normalizes array-valued host headers","Test SSR behind your production proxy topology before deploying"],"tags":["ssr","http","headers","proxy"],"backgroundTag":"malformed-forwarded-header","analyzedSha":"bb72145f9ab45aee29f523236b3a25cd0813a841","analyzedAt":"2026-08-30T02:47:34.745Z","schemaVersion":2},"datasetVersion":"2026-08-30T08:17:16.595Z"}