sveltejs/kit · error · Error

Failed to get response header "set-cookie" — it must be incl

Error message

Failed to get response header "set-cookie" — it must be included by the `filterSerializedResponseHeaders` option: https://svelte.dev/docs/kit/hooks#handle (at ${event.route.id})

What it means

During SSR, SvelteKit wraps a `fetch` response's `headers.getSetCookie` so it can serialize cookies into the page data. Before returning the values it consults the `filterSerializedResponseHeaders` option in your `handle` hook; if the callback returns false for 'set-cookie', the error is thrown instead of silently dropping cookies.

Source

Thrown at packages/kit/src/runtime/server/page/load_data.js:478

				if (value && !lower.startsWith('x-sveltekit-')) {
					const included = resolve_opts.filterSerializedResponseHeaders(lower, value);
					if (!included) {
						throw new Error(
							`Failed to get response header "${lower}" — it must be included by the \`filterSerializedResponseHeaders\` option: https://svelte.dev/docs/kit/hooks#handle (at ${event.route.id})`
						);
					}
				}

				return value;
			};

			const get_set_cookie = response.headers.getSetCookie;
			response.headers.getSetCookie = () => {
				const values = get_set_cookie.call(response.headers);
				for (const value of values) {
					const included = resolve_opts.filterSerializedResponseHeaders('set-cookie', value);
					if (!included) {
						throw new Error(
							`Failed to get response header "set-cookie" — it must be included by the \`filterSerializedResponseHeaders\` option: https://svelte.dev/docs/kit/hooks#handle (at ${event.route.id})`
						);
					}
				}

				return values;
			};
		}

		return proxy;
	};

	// Don't make this function `async`! Otherwise, the user has to `catch` promises they use for streaming responses or else
	// it will be an unhandled rejection. Instead, we add a `.catch(noop)` ourselves below to this from happening.
	return (input, init) => {
		// See docs in fetch.js for why we need to do this
		const response = universal_fetch(input, init);
		response.catch(noop);

View on GitHub (pinned to 03f1687fe6)

Solutions

  1. Update `filterSerializedResponseHeaders` in the `handle` hook to return true for 'set-cookie' when the value should be serialized
  2. If cookies must not leak, stop reading set-cookie from that proxied fetch response and pass session info another way
  3. Guard the header read so getSetCookie is only called when the filter allows it

Example fix

// before
filterSerializedResponseHeaders: (name) => name !== 'set-cookie'
// after
filterSerializedResponseHeaders: (name) => name === 'set-cookie' || name === 'content-type'
Defensive patterns

Strategy: validation

Validate before calling

// in handle hook
const filterSerializedResponseHeaders = (name, value) =>
  name === 'set-cookie' ? shouldSerializeCookie(value) : true;

Prevention

When it happens

Trigger: A `load` function calls SvelteKit's `fetch` on an API whose response contains a `set-cookie` header, while the app's `handle` hook supplies a `filterSerializedResponseHeaders` callback that returns false for ('set-cookie', value), and the code then reads cookies via the wrapped getSetCookie during serialization.

Common situations: Apps that intentionally strip cookies from internal API responses but still have a load function that touches response cookies (e.g. reading session cookies from a backend); developers copying an example `filterSerializedResponseHeaders: (name) => name !== 'set-cookie'` without realizing serialized load data needs the header allowed.

Related errors


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