angular/angular-cli · error · Error
Header "x-forwarded-port" must be a numeric value.
Error message
Header "x-forwarded-port" must be a numeric value.
What it means
Angular SSR requires the trusted `x-forwarded-port` header to be purely numeric (`/^\d+$/`). Only the first value of a comma-separated header is checked. Any non-numeric value on the first port entry causes this throw, protecting against header injection in reconstructed request URLs.
Source
Thrown at packages/angular/ssr/src/utils/validation.ts:215
if (headerValue && !disableHostCheck) {
verifyHostAllowed(headerName, headerValue, allowedHosts);
}
}
const forwarded = headers.get('forwarded');
if (forwarded) {
const forwardedParams = parseForwardedHeader(forwarded);
if (forwardedParams.host && !disableHostCheck) {
verifyHostAllowed('Forwarded "host"', forwardedParams.host, allowedHosts);
}
if (forwardedParams.proto && !VALID_PROTO_REGEX.test(forwardedParams.proto)) {
throw new Error('Header "forwarded" proto parameter must be either "http" or "https".');
}
}
const xForwardedPort = getFirstHeaderValue(headers.get('x-forwarded-port'));
if (xForwardedPort && !VALID_PORT_REGEX.test(xForwardedPort)) {
throw new Error('Header "x-forwarded-port" must be a numeric value.');
}
const xForwardedProto = getFirstHeaderValue(headers.get('x-forwarded-proto'));
if (xForwardedProto && !VALID_PROTO_REGEX.test(xForwardedProto)) {
throw new Error('Header "x-forwarded-proto" must be either "http" or "https".');
}
const xForwardedPrefix = getFirstHeaderValue(headers.get('x-forwarded-prefix'));
if (xForwardedPrefix && !VALID_PREFIX_REGEX.test(xForwardedPrefix)) {
throw new Error(
'Header "x-forwarded-prefix" is invalid. It must start with a "/" and contain ' +
'only alphanumeric characters, hyphens, and underscores, separated by single slashes.',
);
}
}
/**
* Checks if a specific proxy header is allowed.View on GitHub (pinned to bb72145f9a)
Solutions
- Configure the proxy to send a plain numeric port in x-forwarded-port (e.g. `443`).
- Ensure only one x-forwarded-port header is set, set by the trusted proxy itself.
- Remove `x-forwarded-port` from `trustProxyHeaders` if you do not need the port.
- Fix test harnesses to send numeric-only values.
Example fix
// before proxy_set_header X-Forwarded-Port "$server_port/TCP"; // after proxy_set_header X-Forwarded-Port "$server_port";
Defensive patterns
Strategy: validation
Validate before calling
const port = request.headers.get('x-forwarded-port');
const first = port?.split(',')[0].trim();
if (first && !/^\d+$/.test(first)) throw new Error(`Invalid x-forwarded-port: ${first}`); Try / catch
try {
validateHeaders(headers, allowedHosts, disableHostCheck);
} catch (e) {
if ((e as Error).message.includes('x-forwarded-port')) {
return res.status(400).end('Invalid port header');
}
throw e;
} Prevention
- Have exactly one proxy layer emit a plain numeric x-forwarded-port.
- Strip non-numeric annotations at the proxy.
- Only include x-forwarded-port in trustProxyHeaders if you use it.
When it happens
Trigger: A request includes `x-forwarded-port` (and that header is trusted) whose first value is not all digits — e.g. `443, 8080` is fine, but `x-forwarded-port: 443/TCP`, `x-forwarded-port: 443,foo` (first value fine, but `x-forwarded-port: abc`) fails, or multiple merged headers.
Common situations: Reverse proxies appending unusual annotations to the port; load balancers sending multiple port headers that get joined; hand-written integration tests passing malformed values.
Related errors
- Header "x-forwarded-proto" must be either "http" or "https".
- Header "x-forwarded-prefix" is invalid. It must start with a
- Header "${headerName}" with value "${headerValue}" is not al
- Header "forwarded" proto parameter must be either "http" or
- "${TRUST_ALL_PROXY_HEADERS}" is not allowed as a value for t
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/f2ee28e2b9a5288d.
Report an issue: GitHub.