breaking: remove experimental.handleRenderingErrors flag - #16265
Conversation
|
Install the latest version of pnpm add https://pkg.svelte.dev/@sveltejs/kit/c/fa432ff20a8e4c72673143933ae4f6baff3ac03cOpen in |
🦋 Changeset detectedLatest commit: fa432ff The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
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 |
|
gah — this is tricky.
|
… the error status because the reworked `transformError` no longer reassigns the local `status` variable
This commit fixes the issue reported at packages/kit/src/runtime/server/page/render.js:205
## Bug
In `packages/kit/src/runtime/server/page/render.js`, `status` is a mutable destructured parameter of `render_response` (line 59). It is consumed in two places:
- Hydration payload (line 512): `if (status !== 200 && !error) hydrate.push(...)`
- The final HTTP response (line 670): `text(transformed, { status, headers })`
The **base** implementation's `transformError` callback reassigned this closure-scoped variable when an error was caught:
```js
props.page.status = status = transformed.status;
```
The **reworked** callback (commit `2718a1d`) only updated `props.page.status` in both the sync and async branches, dropping the `status = ...` assignment:
```js
props.page.status = error.status; // local `status` never updated
```
## Trigger / failure mode
A page whose `load` succeeds (so `render_response` is invoked with `status: 200`) but whose Svelte component **throws during rendering** and is caught by an error boundary. `transformError` runs, produces e.g. a 500 error object, sets `props.page.status = 500`, but the local `status` stays `200`. The response is then built with `text(transformed, { status: 200 })`, so the client receives an HTTP `200 OK` containing the error page instead of the correct `500`. This is a behavioral regression from the base implementation.
## Fix
Restore the local reassignment in both the sync and async branches:
```js
props.page.status = status = error.status;
```
This keeps the HTTP status code (and the hydration `status` field) in sync with the error status, matching the previous behavior. I left `props.error` unchanged, as the boundary renders the error via the `failed` snippet using the `transformError` return value rather than the root `error` prop.
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: Rich-Harris <hello@rich-harris.dev>
|
I went with 'don't wrap sync |
There was a problem hiding this comment.
One question otherwise LGTM. Update: Nevermind, I should've read the comments before reviewing. But I've gotta say it's somewhat of a big ask - "hey you have an async handleError on the server, you gotta add async: true now whether you want to or not".
Existing async hooks will continue to work for the errors they work for today (i.e. |
…ch can cause an unhandled promise rejection that crashes the server
This commit fixes the issue reported at packages/kit/src/runtime/server/utils.js:122
## Bug
In `handle_error_and_jsonify` (`packages/kit/src/runtime/server/utils.js`), when the user's `handleError` hook returns a `Promise` but the app is **not** running with `compilerOptions.experimental.async` enabled and the error occurs during rendering (`!__SVELTEKIT_SUPPORTS_ASYNC__ && state.is_in_render`), the function warns and returns a generic error object:
```js
if (result instanceof Promise) {
if (!__SVELTEKIT_SUPPORTS_ASYNC__ && state.is_in_render) {
console.warn(...);
return { status, message: 'Internal Error' }; // <-- `result` promise discarded
}
...
}
```
The `result` promise is **discarded without being awaited or given a `.catch()` handler**.
`with_request_store` (`packages/kit/src/exports/internal/server/event.js`) only wraps the call in `try/finally` — **not** `try/catch` — so it passes the promise straight through without attaching any rejection handler:
```js
export function with_request_store(store, fn) {
try {
sync_store = store;
return als ? als.run(store, fn) : fn();
} finally {
if (!IN_WEBCONTAINER) sync_store = null;
}
}
```
Nothing else along the path handles it.
## Concrete trigger
1. User defines an **async** `handleError` hook that can reject (e.g. an `await`ed call to an external logging/Sentry service that throws).
2. `compilerOptions.experimental.async` is **not** enabled — exactly the misconfiguration this branch warns about.
3. A rendering error occurs → `handle_error_and_jsonify` is reached with `state.is_in_render === true` and the hook returns a promise.
4. The warn branch returns the generic object and drops `result`.
5. When `result` later rejects, there is no handler → **unhandled promise rejection**. Under Node.js v15+ default behavior (`--unhandled-rejections=throw`), this can terminate the server process.
## Fix
Attach a no-op `.catch(() => {})` to the discarded promise before returning, preventing the unhandled rejection:
```js
// we're discarding the result, but we still need to prevent an unhandled
// rejection if the user's async `handleError` hook rejects
result.catch(() => {});
return { status, message: 'Internal Error' };
```
This matches the codebase's existing convention for intentionally-ignored promises (`event.js:14`, `core/postbuild/queue.js:20`, `app/server/remote/requested.js:263`).
Co-authored-by: Vercel <vercel[bot]@users.noreply.github.com>
Co-authored-by: Rich-Harris <hello@rich-harris.dev>
This PR was opened by the [Changesets release](https://github.com/changesets/action) GitHub action. When you're ready to do a release, you can merge this and the packages will be published to npm automatically. If you're not ready to do a release yet, that's fine, whenever you add more changesets to version-3, this PR will be updated.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ `version-3` is currently in **pre mode** so this branch has prereleases rather than normal releases. If you want to exit prereleases, run `changeset pre exit` on `version-3`.⚠️ ⚠️ ⚠️ ⚠️ ⚠️ ⚠️ # Releases ## @sveltejs/kit@3.0.0-next.8 ### Major Changes - breaking: remove `experimental.handleRenderingErrors` flag ([#16265](#16265)) - breaking: make `getRequest` and `setResponse` synchronous ([#16280](#16280)) - breaking: make `page.url` immutable on a type level ([#16256](#16256)) - breaking: add `refreshAll` and deprecate `invalidateAll` ([#16289](#16289)) ### Minor Changes - feat: allow hyphens in param and matcher names ([#16284](#16284)) - feat: add `ErrorProps` to generated types ([#16272](#16272)) ### Patch Changes - fix: detect destructured `load` and `actions` exports during type generation ([#16329](#16329)) - fix: ensure CSS URL references are absolute when `paths.relative` is `false` ([#16315](#16315)) - fix: exclude deleted cookies from `cookies.getAll()` so it stays consistent with `cookies.get()` ([#16297](#16297)) - fix: reset failed `<svelte:boundary>` on client navigation so a stale `+error.svelte` is torn down ([#16296](#16296)) - fix: preserve shared client chunk hashes when the app version changes ([#16324](#16324)) - fix: align MAX_COOKIE_SIZE with RFC 6265bis ([#16322](#16322)) - fix: use mouseover+mousemove for preloading to reduce events ([#16325](#16325)) ## @sveltejs/package@3.0.0-next.2 ### Minor Changes - feat: warn when using a `.server.` file or file inside a `server` directory without importing a server-only module ([#16266](#16266)) ## @sveltejs/adapter-auto@8.0.0-next.1 ### Patch Changes - fix: allow prerelease versions of SvelteKit 3 to satisfy the peer dependency range ([#16286](#16286)) - Updated dependencies [[`737d119`](737d119), [`fa78efb`](fa78efb), [`07c207e`](07c207e), [`a47071b`](a47071b), [`14d7d5a`](14d7d5a), [`5c38e51`](5c38e51), [`0702baa`](0702baa), [`e1938c6`](e1938c6), [`8293144`](8293144), [`f76d7d9`](f76d7d9), [`ab5c253`](ab5c253), [`b557b1b`](b557b1b), [`4a513e2`](4a513e2)]: - @sveltejs/kit@3.0.0-next.8 ## @sveltejs/adapter-cloudflare@8.0.0-next.2 ### Patch Changes - fix: allow prerelease versions of SvelteKit 3 to satisfy the peer dependency range ([#16286](#16286)) - Updated dependencies [[`737d119`](737d119), [`fa78efb`](fa78efb), [`07c207e`](07c207e), [`a47071b`](a47071b), [`14d7d5a`](14d7d5a), [`5c38e51`](5c38e51), [`0702baa`](0702baa), [`e1938c6`](e1938c6), [`8293144`](8293144), [`f76d7d9`](f76d7d9), [`ab5c253`](ab5c253), [`b557b1b`](b557b1b), [`4a513e2`](4a513e2)]: - @sveltejs/kit@3.0.0-next.8 ## @sveltejs/adapter-netlify@7.0.0-next.3 ### Patch Changes - fix: include `utils.js` in package.json `files` ([#16298](#16298)) - Updated dependencies [[`737d119`](737d119), [`fa78efb`](fa78efb), [`07c207e`](07c207e), [`a47071b`](a47071b), [`14d7d5a`](14d7d5a), [`5c38e51`](5c38e51), [`0702baa`](0702baa), [`e1938c6`](e1938c6), [`8293144`](8293144), [`f76d7d9`](f76d7d9), [`ab5c253`](ab5c253), [`b557b1b`](b557b1b), [`4a513e2`](4a513e2)]: - @sveltejs/kit@3.0.0-next.8 ## @sveltejs/adapter-node@6.0.0-next.3 ### Patch Changes - fix: allow prerelease versions of SvelteKit 3 to satisfy the peer dependency range ([#16286](#16286)) - Updated dependencies [[`737d119`](737d119), [`fa78efb`](fa78efb), [`07c207e`](07c207e), [`a47071b`](a47071b), [`14d7d5a`](14d7d5a), [`5c38e51`](5c38e51), [`0702baa`](0702baa), [`e1938c6`](e1938c6), [`8293144`](8293144), [`f76d7d9`](f76d7d9), [`ab5c253`](ab5c253), [`b557b1b`](b557b1b), [`4a513e2`](4a513e2)]: - @sveltejs/kit@3.0.0-next.8 ## @sveltejs/adapter-static@4.0.0-next.1 ### Patch Changes - fix: allow prerelease versions of SvelteKit 3 to satisfy the peer dependency range ([#16286](#16286)) - Updated dependencies [[`737d119`](737d119), [`fa78efb`](fa78efb), [`07c207e`](07c207e), [`a47071b`](a47071b), [`14d7d5a`](14d7d5a), [`5c38e51`](5c38e51), [`0702baa`](0702baa), [`e1938c6`](e1938c6), [`8293144`](8293144), [`f76d7d9`](f76d7d9), [`ab5c253`](ab5c253), [`b557b1b`](b557b1b), [`4a513e2`](4a513e2)]: - @sveltejs/kit@3.0.0-next.8 ## @sveltejs/adapter-vercel@7.0.0-next.2 ### Patch Changes - fix: allow prerelease versions of SvelteKit 3 to satisfy the peer dependency range ([#16286](#16286)) - Updated dependencies [[`737d119`](737d119), [`fa78efb`](fa78efb), [`07c207e`](07c207e), [`a47071b`](a47071b), [`14d7d5a`](14d7d5a), [`5c38e51`](5c38e51), [`0702baa`](0702baa), [`e1938c6`](e1938c6), [`8293144`](8293144), [`f76d7d9`](f76d7d9), [`ab5c253`](ab5c253), [`b557b1b`](b557b1b), [`4a513e2`](4a513e2)]: - @sveltejs/kit@3.0.0-next.8 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Removes the flag, as this is the default behaviour in SvelteKit 3
Please don't delete this checklist! Before submitting the PR, please make sure you do the following:
Tests
pnpm testand lint the project withpnpm lintandpnpm checkChangesets
pnpm changesetand following the prompts. Changesets that add features should beminorand those that fix bugs should bepatch. Please prefix changeset messages withfeat:,fix:, orchore:.Edits