sveltejs / kit

web development, streamlined
https://kit.svelte.dev
MIT License
18.61k stars 1.92k forks source link

`handleError` from hooks.client does not handle thrown Error #10169

Open brandonp-ais opened 1 year ago

brandonp-ais commented 1 year ago

Describe the bug

Unexpected errors should be passed to hooks.client.js#handleError() so they could be sent to Sentry etc.

https://kit.svelte.dev/docs/hooks#shared-hooks-handleerror

But if a new Error() is thrown from top level of a +page.svelte script tag, the app crashes and the hook is not invoked.

I would expect that such an error, which is mimicking an unexpected error, should be picked up by the hook.

Reproduction

Stackblitz reproduction

Logs

proxy.js?v=edb02b92:15 [HMR][Svelte] Unrecoverable HMR error in <+page>: next update will trigger a full reload
logError @ proxy.js?v=edb02b92:15
Proxy<+page> @ proxy.js?v=edb02b92:380
construct_svelte_component_dev @ chunk-CKECMU6L.js?v=edb02b92:2110
update @ root.svelte:42
update_slot_base @ chunk-CKECMU6L.js?v=edb02b92:97
update @ +layout.svelte:14
update @ chunk-CKECMU6L.js?v=edb02b92:1140
flush @ chunk-CKECMU6L.js?v=edb02b92:1106
Show 1 more frame
+page.svelte:11 Uncaught (in promise) Error: Will you see this error?
    at instance (+page.svelte:11:29)
    at init (chunk-CKECMU6L.js?v=edb02b92:1890:23)
    at new Page (+page.svelte:3:45)
    at createProxiedComponent (svelte-hooks.js?v=edb02b92:341:9)
    at new ProxyComponent (proxy.js?v=edb02b92:242:7)
    at new Proxy<+page> (proxy.js?v=edb02b92:349:11)
    at construct_svelte_component_dev (chunk-CKECMU6L.js?v=edb02b92:2110:22)
    at Object.update [as p] (root.svelte:42:41)
    at update_slot_base (chunk-CKECMU6L.js?v=edb02b92:97:10)
    at Object.update [as p] (+layout.svelte:14:63)
instance @ +page.svelte:11
init @ chunk-CKECMU6L.js?v=edb02b92:1890
Page @ +page.svelte:3
createProxiedComponent @ svelte-hooks.js?v=edb02b92:341
ProxyComponent @ proxy.js?v=edb02b92:242
Proxy<+page> @ proxy.js?v=edb02b92:349
construct_svelte_component_dev @ chunk-CKECMU6L.js?v=edb02b92:2110
update @ root.svelte:42
update_slot_base @ chunk-CKECMU6L.js?v=edb02b92:97
update @ +layout.svelte:14
update @ chunk-CKECMU6L.js?v=edb02b92:1140
flush @ chunk-CKECMU6L.js?v=edb02b92:1106
Show 1 more frame
blitz.a12d8c69.js:44 Proxy(Error) {stack: 'Error: Will you see this error?\n    at eval (/home…tejs/kit/src/runtime/server/page/index.js:295:10)', message: 'Will you see this error?'}
consoleCall @ blitz.a12d8c69.js:44
#options.hooks.handleError @ index.js:44
handle_error_and_jsonify @ utils.js:115
respond_with_error @ respond_with_error.js:87
await in respond_with_error (async)
render_page @ index.js:305
await in render_page (async)
resolve @ respond.js:397
resolve @ respond.js:269
#options.hooks.handle @ index.js:43
respond @ respond.js:266
await in respond (async)
respond @ index.js:75
eval @ index.js:522
await in eval (async)
call @ dep-e8f070e8.js:49107
next @ dep-e8f070e8.js:49051
viteServeRawFsMiddleware @ dep-e8f070e8.js:46178
call @ dep-e8f070e8.js:49107
next @ dep-e8f070e8.js:49051
viteTransformMiddleware @ dep-e8f070e8.js:61637
await in viteTransformMiddleware (async)
call @ dep-e8f070e8.js:49107
next @ dep-e8f070e8.js:49051
eval @ dep-e8f070e8.js:45971
viteServePublicMiddleware @ dep-e8f070e8.js:46101
call @ dep-e8f070e8.js:49107
next @ dep-e8f070e8.js:49051
viteHMRPingMiddleware @ dep-e8f070e8.js:63543
call @ dep-e8f070e8.js:49107
next @ dep-e8f070e8.js:49051
next @ dep-e8f070e8.js:49029
cors @ dep-e8f070e8.js:49579
eval @ dep-e8f070e8.js:49615
originCallback @ dep-e8f070e8.js:49605
eval @ dep-e8f070e8.js:49610
optionsCallback @ dep-e8f070e8.js:49590
corsMiddleware @ dep-e8f070e8.js:49595
call @ dep-e8f070e8.js:49107
next @ dep-e8f070e8.js:49051
eval @ index.js:408
call @ dep-e8f070e8.js:49107
next @ dep-e8f070e8.js:49051
handle @ dep-e8f070e8.js:49054
app @ dep-e8f070e8.js:48919
EventEmitter.emit @ events.js:526
parserOnIncoming @ _http_server.js:951
parserOnHeadersComplete @ _http_common.js:128
(anonymous) @ blitz.a12d8c69.js:44
_0x2e75e9 @ blitz.a12d8c69.js:44
(anonymous) @ blitz.a12d8c69.js:44
my-error:1     Failed to load resource: the server responded with a status of 500 (Internal Server Error)

System Info

New sveltejs-kit-template-default on stackblitz

Severity

serious, but I can work around it

Additional Information

No response

ildella commented 1 year ago

This is part of a larger problem I am having.

Catching unexpected server errors in hooks.server is of no use, if not for logging purpose.

One is then forced to try/catch or if/else their way in every server side handler - which is very inefficient.

What I would find more efficient is for the global error catch - hooks.server - to be able to handle errors: maybe throw a nicer error catched by hooks.client that could for example redirect to nice error page, redirect to authentication...

Would this have wrong side effects?

So either is like that or I am missing something big :)

But how would one handle this scenario:

  1. user land on a random legit URL with an expired / false token in the cookie
  2. the server pick the cookie and invoke some other HTTP service - that returns 401/403.
  3. the error is thrown and the error ends up in hooks.server

if is a 401/3 I Would like to send user to /auth. If is something else, I would handle it differently.

What I don't think is good is go try/catch server side code everywhere.

ibrahimqasim-abtrace commented 9 months ago

This is especially an issue with SPAs with no SSR. There is no way to globally handle errors with some error component.

phobetron commented 7 months ago

From our own testing, the core issue is when code in the hook modules, specifically universal and client hook modules, are being loaded and executed.

We had an internal expectation that code in hook modules would load and execute before any other code, so we placed code that we wanted to be executed before anything else in those modules. We had assumed that, if supported hooks were going to function as expected just as the case in this issue, then they'd need to load and run first. However, this is not the case.

The fact that the hooks don't load before a +page file is executed means the behavior of hooks is either incorrect or less useful than we would hope. The fact that code in hooks modules don't execute before any other code (+page or otherwise, like in $lib) may or may not be incorrect behavior, but how and when these hook modules load and execute should be better documented so that we may be better able to decide how we may make use of them.