Describe the bug
With link preloading on (data-sveltekit-preload-data="hover"), a failed data request for a hovered link leaves an unhandled promise rejection in production builds.
When the __data.json request for the preloaded route fails (the network drops or cancels it), load_route passes the error through handleError and then, because the load is a preload, rethrows the handled App.Error:
if (preload && preload_tokens.has(preload)) {
throw await handle_error(err, { params, url, route: { id: route.id } });
}
In development the hover handler catches this (void _preload_data(intent).catch(...), which logs the preload warning). The production branch is void _preload_data(intent); with no handler, so the rejection is unhandled.
Anything listening for unhandledrejection, such as an error tracker's default global handlers, then records a second event for the same failure: a plain object like {"status":500,"message":"Internal Error"} with no stack, after handleError has already reported the real error. preloadData() catches the same throw and returns { type: 'error' }, so only the hover/tap path is affected. The 2.x line returns a preload_error(...) result instead of throwing, so it does not have this problem.
Reproduction
- A page with a link to another route whose
load runs on the server (so the preload fetches __data.json), and data-sveltekit-preload-data="hover" on <body>.
vite build && vite preview.
- Register
window.addEventListener('unhandledrejection', (e) => console.log(e.reason)).
- Make the target's
__data.json request fail — DevTools request blocking, or in Playwright page.route((url) => url.pathname.endsWith('/__data.json'), (route) => route.abort('failed')) — then hover the link.
The listener logs the handled App.Error object. Under vite dev the same steps only print the preload warning.
Logs
unhandledrejection: {"status":500,"message":"Internal Error"}
System Info
@sveltejs/kit 3.0.0-next.27
svelte 5.57.0
vite 8.2.2
@sveltejs/vite-plugin-svelte 7.3.0
Chromium (Playwright 1.63.0)
Severity
annoyance
Additional Information
Catching in the production branch the way the development branch does fixes it for us — the error has already been through handleError:
} else {
void _preload_data(intent).catch(noop);
}
We carry that as a local patch for now. Porting the 2.x preload_error approach would also work.
Describe the bug
With link preloading on (
data-sveltekit-preload-data="hover"), a failed data request for a hovered link leaves an unhandled promise rejection in production builds.When the
__data.jsonrequest for the preloaded route fails (the network drops or cancels it),load_routepasses the error throughhandleErrorand then, because the load is a preload, rethrows the handledApp.Error:In development the hover handler catches this (
void _preload_data(intent).catch(...), which logs the preload warning). The production branch isvoid _preload_data(intent);with no handler, so the rejection is unhandled.Anything listening for
unhandledrejection, such as an error tracker's default global handlers, then records a second event for the same failure: a plain object like{"status":500,"message":"Internal Error"}with no stack, afterhandleErrorhas already reported the real error.preloadData()catches the same throw and returns{ type: 'error' }, so only the hover/tap path is affected. The 2.x line returns apreload_error(...)result instead of throwing, so it does not have this problem.Reproduction
loadruns on the server (so the preload fetches__data.json), anddata-sveltekit-preload-data="hover"on<body>.vite build && vite preview.window.addEventListener('unhandledrejection', (e) => console.log(e.reason)).__data.jsonrequest fail — DevTools request blocking, or in Playwrightpage.route((url) => url.pathname.endsWith('/__data.json'), (route) => route.abort('failed'))— then hover the link.The listener logs the handled
App.Errorobject. Undervite devthe same steps only print the preload warning.Logs
System Info
Severity
annoyance
Additional Information
Catching in the production branch the way the development branch does fixes it for us — the error has already been through
handleError:We carry that as a local patch for now. Porting the 2.x
preload_errorapproach would also work.