angular/angular-cli · error · Error
Header "${headerName}" contains an invalid value and cannot
Error message
Header "${headerName}" contains an invalid value and cannot be parsed. What it means
verifyHostAllowed interprets a forwarded-host header value (e.g. X-Forwarded-Host) by parsing it as 'http://<value>'. If the value cannot be parsed as a URL at all (it contains characters illegal in a hostname), it throws instead of trusting it. This prevents malformed header injection from reaching host validation.
Source
Thrown at packages/angular/ssr/src/utils/validation.ts:141
: request;
}
/**
* Validates a specific host header value against the allowed hosts.
*
* @param headerName - The name of the header to validate (e.g., 'host', 'x-forwarded-host').
* @param headerValue - The value of the header to validate.
* @param allowedHosts - A set of allowed hostnames.
* @throws Error if the header value is invalid or the hostname is not in the allowlist.
*/
function verifyHostAllowed(
headerName: string,
headerValue: string,
allowedHosts: ReadonlySet<string>,
): void {
const url = `http://${headerValue}`;
if (!URL.canParse(url)) {
throw new Error(`Header "${headerName}" contains an invalid value and cannot be parsed.`);
}
const { hostname, pathname, search, hash, username, password } = new URL(url);
if (pathname !== '/' || search || hash || username || password) {
throw new Error(
`Header "${headerName}" with value "${headerValue}" contains characters that are not allowed.`,
);
}
if (!isHostAllowed(hostname, allowedHosts)) {
throw new Error(`Header "${headerName}" with value "${headerValue}" is not allowed.`);
}
}
/**
* Checks if the hostname is allowed.
* @param hostname - The hostname to check.
* @param allowedHosts - A set of allowed hostnames.View on GitHub (pinned to bb72145f9a)
Solutions
- Find the client/proxy sending the malformed header and fix or drop it (configure the proxy to sanitize X-Forwarded-Host).
- Send only a bare hostname (no scheme, no path) in X-Forwarded-Host.
- If the header is not needed, remove it at the reverse proxy so validateHeaders sees a clean request.
Example fix
// before (client request)
fetch(url, { headers: { 'X-Forwarded-Host': 'https://example.com' } });
// after
fetch(url, { headers: { 'X-Forwarded-Host': 'example.com' } }); Defensive patterns
Strategy: validation
Validate before calling
const fwh = request.headers.get('x-forwarded-host');
if (fwh && !URL.canParse(`http://${fwh}`)) {
return new Response('Bad Request', { status: 400 });
} Type guard
function isParsableHostHeader(value: string): boolean {
return URL.canParse(`http://${value}`);
} Try / catch
try {
await render(request);
} catch (e) {
if (e instanceof Error && e.message.includes('cannot be parsed.')) {
return new Response('Bad Request: malformed host header', { status: 400 });
} throw e;
} Prevention
- Send only bare hostnames (no scheme, path, or credentials) in X-Forwarded-Host.
- Sanitize or strip forwarded headers at the edge proxy before they reach the SSR server.
- Only trust X-Forwarded-* from known proxy IPs; drop them from external clients.
When it happens
Trigger: A client sends a Host-related header such as X-Forwarded-Host containing characters that make 'http://<value>' unparseable — e.g. spaces, control characters, multiple comma-joined values with junk, or '@'/'%' sequences that break URL parsing.
Common situations: Malicious or buggy proxies appending junk to X-Forwarded-Host; clients sending a full URL (including scheme) in the header; fuzzing/scanning traffic hitting a public SSR endpoint.
Related errors
- Header "${headerName}" with value "${headerValue}" contains
- URL with hostname "${hostname}" is not allowed.
- Header "${headerName}" with value "${headerValue}" is not al
- Header "forwarded" proto parameter must be either "http" or
- Header "x-forwarded-port" must be a numeric value.
AI-assisted analysis of angular/angular-cli@bb72145f9a (2026-08-30).
Data as JSON: /api/errors/9aa52921cd1ab21f.
Report an issue: GitHub.