Skip to content

fix: don't mask errors with a "header is already set" error when rendering the error page - #16323

Open
Nic-Polumeyv wants to merge 3 commits into
sveltejs:version-3from
Nic-Polumeyv:fix-error-page-setheaders
Open

fix: don't mask errors with a "header is already set" error when rendering the error page#16323
Nic-Polumeyv wants to merge 3 commits into
sveltejs:version-3from
Nic-Polumeyv:fix-error-page-setheaders

Conversation

@Nic-Polumeyv

@Nic-Polumeyv Nic-Polumeyv commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

If the root layout load calls setHeaders and something throws after the page rendered, the error page dies too. respond_with_error re-runs the root layout load on the same event, so the second setHeaders call hits the set-once check and throws "cache-control" header is already set. That error replaces the real one in handle_error_and_jsonify, so the log shows only the setHeaders complaint and the response falls back to the static error page instead of +error.svelte.

The set-once throw is by design (#5778) and stays untouched. Instead, resolve snapshots the headers handle has set before any route logic runs, and respond_with_error restores that snapshot before rendering, so the error page starts from the post-handle state and the re-run root layout load sets its headers on a clean slate. Headers the failed render set for the page that never shipped are dropped rather than leaked onto the error response, and server-timing no longer doubles up during the re-run. locals and cookies are deliberately left alone, a shallow copy can't undo mutations to nested state and rolling back a session cookie on an error page would log people out.

Finding a trigger takes more care here than on kit 2. load errors take the nearest-boundary path without re-running the root layout, and on version-3 render errors are caught in place by the root <svelte:boundary> too, so neither reaches respond_with_error anymore. Anything that throws after the loads settled still does, transformPageChunk in the tests' case, and so does a page module that fails to import (the trigger in the original issue).

Fixes #11676

@pkg-svelte-dev

pkg-svelte-dev Bot commented Jul 10, 2026

Copy link
Copy Markdown

Install the latest version of @sveltejs/kit from 097ae7d:

pnpm add https://pkg.svelte.dev/@sveltejs/kit/c/097ae7d6c082db46ca16a4d59410ac35a16f4fa9

Open in pkg.svelte.dev: https://pkg.svelte.dev/repos/kit/pr/16323

Note

This PR is from a fork. A maintainer must approve approve each commit before it can be built and installed.

@changeset-bot

changeset-bot Bot commented Jul 10, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 097ae7d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@sveltejs/kit Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@Nic-Polumeyv
Nic-Polumeyv changed the base branch from main to version-3 July 15, 2026 01:07
@Nic-Polumeyv
Nic-Polumeyv force-pushed the fix-error-page-setheaders branch from 5767856 to 037aa33 Compare July 15, 2026 01:07
@Nic-Polumeyv

Copy link
Copy Markdown
Contributor Author

Since #16664 this masking got worse: the synthetic "header is already set" error reaches handleError as `kind: 'unknown', so it shows up in user telemetry as an app bug while the original error is dropped.

@Rich-Harris

Copy link
Copy Markdown
Member

Looks like #11676 is fixed on v3, though the test in this PR still fails on version-3.

I think the correct fix here is to roll back any headers (and locals, and possibly other things?) that were set by the route before attempting to render the error page, because that's the real issue here — the second setHeaders(...) call shouldn't trigger the 'already set' error because we should be rendering the error page from scratch, without the leftover state from the half-run logic that preceded it.

@Nic-Polumeyv
Nic-Polumeyv force-pushed the fix-error-page-setheaders branch from 037aa33 to bbc87cf Compare August 30, 2026 22:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Incorrect "Cache-Control" Error Message in SvelteKit when Protected Route has Import Issue

2 participants