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

  1. Fix the proxy to send only the scheme, e.g. x-forwarded-proto: https
  2. Restrict which headers are trusted via PROTOCOL_HEADER to ones your proxy overwrites on every request
  3. 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

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


AI-assisted analysis of sveltejs/kit@03f1687fe6 (2026-09-02). Data as JSON: /api/errors/6504f237171b9409. Report an issue: GitHub.