-
-
Notifications
You must be signed in to change notification settings - Fork 2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Thrown exceptions from __layout.svelte load result in plain text error responses #3068
Comments
The issue seems to be in https://github.com/sveltejs/kit/blob/master/packages/kit/src/runtime/server/page/respond_with_error.js where the first call to |
Implementation aside, I'm now having a bit of a question about what the desired behavior even is. Currently, when the layout The behavior here when |
What I have right now is diff --git a/packages/kit/src/runtime/server/page/load_node.js b/packages/kit/src/runtime/server/page/load_node.js
index 9cb9b1b8..4c4c6a52 100644
--- a/packages/kit/src/runtime/server/page/load_node.js
+++ b/packages/kit/src/runtime/server/page/load_node.js
@@ -2,6 +2,7 @@ import { normalize } from '../../load.js';
import { respond } from '../index.js';
import { escape_json_string_in_html } from '../../../utils/escape.js';
import { is_root_relative, resolve } from '../../../utils/url.js';
+import { coalesce_to_error } from '../../../utils/error.js';
const s = JSON.stringify;
@@ -282,7 +283,15 @@ export async function load_node({
/** @type {import('types/page').ErrorLoadInput} */ (load_input).error = error;
}
- loaded = await module.load.call(null, load_input);
+ try {
+ loaded = await module.load.call(null, load_input);
+ } catch (err) {
+ if (!is_leaf && !is_error) {
+ loaded = { status: 500, error: coalesce_to_error(err) };
+ } else {
+ throw err;
+ }
+ }
} else {
loaded = {};
} which appears to break a number of existing tests, and also doesn't call Edit: Whoops, fixed typo. There's no failing tests now, at least. I'm still not sure whether this is the right track. |
I'm feeling a little better about this: diff --git a/packages/kit/src/runtime/server/page/load_node.js b/packages/kit/src/runtime/server/page/load_node.js
index 9cb9b1b8..02bd9ac9 100644
--- a/packages/kit/src/runtime/server/page/load_node.js
+++ b/packages/kit/src/runtime/server/page/load_node.js
@@ -1,5 +1,6 @@
import { normalize } from '../../load.js';
import { respond } from '../index.js';
+import { coalesce_to_error } from '../../../utils/error.js';
import { escape_json_string_in_html } from '../../../utils/escape.js';
import { is_root_relative, resolve } from '../../../utils/url.js';
@@ -18,6 +19,7 @@ const s = JSON.stringify;
* prerender_enabled: boolean;
* is_leaf: boolean;
* is_error: boolean;
+ * handle_error: any | undefined;
* status?: number;
* error?: Error;
* }} opts
@@ -35,6 +37,7 @@ export async function load_node({
prerender_enabled,
is_leaf,
is_error,
+ handle_error,
status,
error
}) {
@@ -282,7 +285,16 @@ export async function load_node({
/** @type {import('types/page').ErrorLoadInput} */ (load_input).error = error;
}
- loaded = await module.load.call(null, load_input);
+ try {
+ loaded = await module.load.call(null, load_input);
+ } catch (err) {
+ if (handle_error) {
+ handle_error(err);
+ loaded = { status: 500, error: coalesce_to_error(err) };
+ } else {
+ throw err;
+ }
+ }
} else {
loaded = {};
}
diff --git a/packages/kit/src/runtime/server/page/respond_with_error.js b/packages/kit/src/runtime/server/page/respond_with_error.js
index 986a788b..97f82de3 100644
--- a/packages/kit/src/runtime/server/page/respond_with_error.js
+++ b/packages/kit/src/runtime/server/page/respond_with_error.js
@@ -43,7 +43,8 @@ export async function respond_with_error({ request, options, state, $session, st
stuff: {},
prerender_enabled: is_prerender_enabled(options, default_error, state),
is_leaf: false,
- is_error: false
+ is_error: false,
+ handle_error: err => options.handle_error(err, request)
})
); (although it still has some type issues). In this case, |
I think #3239 fixed this by calling respond_with_error after handler_error is run. At least I'm seeing the __error.svelte page when throwing an exception in a load function (tested with the hn example). However the originally thrown exception with my message is not shown. Instead im seeing this: |
The behavior here hasn't changed, at least as far as I can tell. It's also unclear to me how the |
A bit tangential, but would it make sense if we leave it as is, but for dev mode, we show VIte's error overlay of the thrown error? This could differentiate between expected error (from |
🤷 I mention in the "Additional Information" section specifically why I'm looking for this behavior. I currently have to duplicate some |
@Conduitry @bluwy Are you still seeing this with the latest SvelteKit? I think things have been improved. I see the error reported in the |
I'm still seeing in |
I'm not sure if this is the same issue, but a similar thing happens when you navigate (with Javascript enabled) to a page where a shadow endpoint throws an error. Rather than the error message thrown by the endpoint I get "Failed to load data". Few other notes:
Here's a minimal repro: https://github.com/cdcarson/svelte-throw-endpoint-error-issue
I'm using SvelteKit v1.0.0-next.302. Let me know if this needs to be a separate issue. Not being able to throw errors consistently is a pretty fundamental flaw/stumbling block. Thanks. |
The problem occurs when the root layout throws an error. Other layouts are not rerun, but the root layout is still rerun in the "fall back to something" case. I think the solution to this and #2154 is to not use the user-defined root layout if it exists but rather always have one layout above that which is just a |
It's now possible to src/routes/
├ (main)
│ ├ foo/
│ ├ bar/
│ ├ etc/
│ ├ +layout.svelte # can safely throw errors in here
│ └ +page.svelte
├ +error.svelte
└ +layout.svelte # optional ...which mostly solves this issue. That said, there are always going to be cases where we need to bail out to something (e.g. the Right now, that's a plain text response. I think we should make that a more appealing HTML page — something very basic, but nicer than what we currently have — and allow people to create a Unlike Changing the plain text error response to HTML would be a breaking change, so I've added the label. |
This is a static error page that will be rendered by the server when everything else goes wrong Closes #3068
* [breaking] add error.html This is a static error page that will be rendered by the server when everything else goes wrong Closes #3068 * await native navigations to prevent content flashes * thank you test for uncovering my inability to set the response's content-type * error page can retrieve status / message * fix test * shhh * note placeholders * move default error template into separate file * add some super basic css * fix test * rename options * remove error.html from create-svelte * fix tests * rename internal, too * fixes * Update documentation/docs/03-routing.md Co-authored-by: Rich Harris <hello@rich-harris.dev> Co-authored-by: Rich Harris <richard.a.harris@gmail.com>
Describe the bug
Throwing an exception (or returning a rejecting promise) from a
load
function should be equivalent to returning{ status: 500, error }
(apart from the former also resulting in a call to thehandleError
hook). However, currently, it results in a plain text error message response from the server, which should be returned only when the__error.svelte
component fails to render.Reproduction
Starting from the demo app, add this to
__layout.svelte
:Navigate to any page.
Logs
No response
System Info
Severity
serious, but I can work around it
Additional Information
This is inconvenient because I'd like to use the
handleError
hook as the sole place for performing certain kinds of error logging, but I'd also prefer to not return a plain text error response to users. This means that currently my__layout.svelte
'sload
function needs to catch the error and reimplement thehandleError
handling in a different way (since it has access toload
arguments instead of to therequest
object).The text was updated successfully, but these errors were encountered: