sveltejs/kit · error · Error

The ${protocol_header} header specified ${protocol} which is

Error message

The ${protocol_header} header specified ${protocol} which is an invalid protocol scheme. It should only contain the protocol scheme (e.g. `https`)

What it means

When a PROTOCOL_HEADER is configured, adapter-bun derives the request origin's scheme from that header. It only accepts http or https; any other value (or a full URL) is rejected because the header must contain just the protocol scheme.

Source

Thrown at packages/adapter-bun/src/handler.js:73

		console.error(
			`Could not determine request origin: ${error instanceof Error ? error.message : String(error)}`
		);
		return new Response('Bad Request', { status: 400 });
	}
}

/**
 * @param {Request} request
 * @param {URL} url
 * @returns {string}
 */
function get_origin(request, url) {
	// assume TLS terminates upstream, like adapter-node; an http origin would fail CSRF checks
	const protocol = decodeURIComponent(
		(protocol_header && request.headers.get(protocol_header)) || 'https'
	);
	if (!/^https?$/i.test(protocol)) {
		throw new Error(
			`The ${protocol_header} header specified ${protocol} which is an invalid protocol scheme. It should only contain the protocol scheme (e.g. \`https\`)`
		);
	}

	const host =
		(host_header && request.headers.get(host_header)) || (request.headers.get('host') ?? url.host);
	if (!host) {
		throw new Error(
			`Could not determine host from the ${host_header ? `${host_header} or ` : ''}host header`
		);
	}

	const port = port_header ? request.headers.get(port_header) : null;
	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 bare scheme, e.g. nginx: `proxy_set_header X-Forwarded-Proto $scheme;`
  2. Verify the header name matches the PROTOCOL_HEADER env var you configured.
  3. If TLS does not terminate upstream, unset PROTOCOL_HEADER so the default 'https' is used.

Example fix

// nginx before
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.get('x-forwarded-proto') || 'https').trim();
if (!/^https?$/i.test(proto)) throw new Error(`Bad forwarded protocol: ${proto}`);

Try / catch

try {
  origin = getOrigin(req);
} catch (err) {
  if (/invalid protocol scheme/.test(err.message)) {
    console.error('Fix proxy to send bare scheme in the protocol header');
  }
  throw err;
}

Prevention

When it happens

Trigger: A reverse proxy sends `Protocol: https://example.com` or `X-Forwarded-Proto: HTTP/1.1` instead of a bare scheme; misconfigured proxy passing the full origin into the protocol header.

Common situations: Nginx/Cloudflare misconfiguration where the forwarded proto header includes a host or trailing slash; apps behind proxies that set custom protocol headers with full URLs.

Related errors


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