sveltejs/kit · error · Error
The ${protocol_header} header specified ${protocol} which is
Error message
The ${protocol_header} header specified ${protocol} which is an invalid because it includes `:`. It should only contain the protocol scheme (e.g. `https`) What it means
adapter-node builds the request origin from the configured PROTOCOL_HEADER value. To prevent host/protocol injection, the value must be a bare scheme; if the decoded protocol contains ':' (e.g. a full URL 'https://evil.com') the server rejects it.
Source
Thrown at packages/adapter-node/src/handler.js:250
throw new Error(
`Multiple values provided for ${name} header where only one expected: ${value}`
);
}
return value;
}
/**
* @param {IncomingHttpHeaders} headers
* @returns {string}
*/
function get_origin(headers) {
const protocol = decodeURIComponent(
normalise_header(protocol_header, headers[protocol_header]) || 'https'
);
// this helps us avoid host injections through the protocol header
if (protocol.includes(':')) {
throw new Error(
`The ${protocol_header} header specified ${protocol} which is an invalid because it includes \`:\`. It should only contain the protocol scheme (e.g. \`https\`)`
);
}
const host =
normalise_header(host_header, headers[host_header]) ||
normalise_header('host', headers['host']);
if (!host) {
const header_names = host_header ? `${host_header} or host headers` : 'host header';
throw new Error(
`Could not determine host. The request must have a value provided by the ${header_names}`
);
}
const port = normalise_header(port_header, headers[port_header]);
if (port && isNaN(+port)) {
throw new Error(
`The ${port_header} header specified ${port} which is an invalid port because it is not a number. The value should only contain the port number (e.g. 443)`View on GitHub (pinned to 03f1687fe6)
Solutions
- Fix the proxy to send only the scheme, e.g. x-forwarded-proto: https
- Restrict which headers are trusted via PROTOCOL_HEADER to ones your proxy overwrites on every request
- Sanitize/normalize the header at the proxy layer, stripping anything after the scheme
Example fix
// before (proxy) proxy_set_header x-forwarded-proto $scheme://$host; // after proxy_set_header x-forwarded-proto $scheme;
Defensive patterns
Strategy: validation
Validate before calling
const proto = req.headers['x-forwarded-proto'];
if (typeof proto === 'string' && proto.includes(':')) {
throw new Error('x-forwarded-proto must be a bare scheme like https');
} Type guard
function isBareScheme(v) {
return typeof v === 'string' && /^[a-z][a-z0-9+.-]*$/.test(v);
} Try / catch
try {
origin = getOrigin(headers);
} catch (err) {
if (String(err.message).includes('includes `:`')) {
console.error('Protocol header carries a full URL; proxy must send only the scheme');
} else {
throw err;
}
} Prevention
- Proxy must send only the scheme (e.g. $scheme), never a URL
- Only trust headers your own proxy overwrites per request
- Add an integration test asserting the built origin for sample headers
When it happens
Trigger: A request arrives whose PROTOCOL_HEADER (e.g. x-forwarded-proto) value includes a colon after decodeURIComponent — typically someone injecting 'https://attacker' instead of 'https'.
Common situations: Proxies passing a full origin URL in x-forwarded-proto, or malicious clients sending crafted headers when the header is publicly settable.
Related errors
- The ${port_header} header specified ${port} which is an inva
- Address header was specified with ${env_prefix + 'ADDRESS_HE
- ${env_prefix + 'XFF_DEPTH'} must be a positive integer
- ${env_prefix + 'XFF_DEPTH'} is ${xff_depth}, but only found
- Multiple values provided for ${name} header where only one e
AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02).
Data as JSON: /api/errors/6504f237171b9409.
Report an issue: GitHub.