From a23599a196380ce7fc3fb374dac4daee173776b7 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Sun, 13 Jul 2025 18:20:29 -0400 Subject: [PATCH] fix: don't show adjusted error messages in boundaries (#16360) --- .changeset/large-balloons-agree.md | 5 ++ .../src/internal/client/error-handling.js | 47 ++++++++++++------- .../samples/error-boundary-3/_config.js | 2 +- .../samples/error-boundary-3/main.svelte | 6 +-- 4 files changed, 38 insertions(+), 22 deletions(-) create mode 100644 .changeset/large-balloons-agree.md diff --git a/.changeset/large-balloons-agree.md b/.changeset/large-balloons-agree.md new file mode 100644 index 0000000000..9355336862 --- /dev/null +++ b/.changeset/large-balloons-agree.md @@ -0,0 +1,5 @@ +--- +'svelte': patch +--- + +fix: don't show adjusted error messages in boundaries diff --git a/packages/svelte/src/internal/client/error-handling.js b/packages/svelte/src/internal/client/error-handling.js index 378f7408ef..b12f21adfc 100644 --- a/packages/svelte/src/internal/client/error-handling.js +++ b/packages/svelte/src/internal/client/error-handling.js @@ -7,14 +7,16 @@ import { BOUNDARY_EFFECT, EFFECT_RAN } from './constants.js'; import { define_property, get_descriptor } from '../shared/utils.js'; import { active_effect } from './runtime.js'; +const adjustments = new WeakMap(); + /** * @param {unknown} error */ export function handle_error(error) { var effect = /** @type {Effect} */ (active_effect); - if (DEV && error instanceof Error) { - adjust_error(error, effect); + if (DEV && error instanceof Error && !adjustments.has(error)) { + adjustments.set(error, get_adjustments(error, effect)); } if ((effect.f & EFFECT_RAN) === 0) { @@ -48,21 +50,19 @@ export function invoke_error_boundary(error, effect) { effect = effect.parent; } + if (error instanceof Error) { + apply_adjustments(error); + } + throw error; } -/** @type {WeakSet} */ -const adjusted_errors = new WeakSet(); - /** * Add useful information to the error message/stack in development * @param {Error} error * @param {Effect} effect */ -function adjust_error(error, effect) { - if (adjusted_errors.has(error)) return; - adjusted_errors.add(error); - +function get_adjustments(error, effect) { const message_descriptor = get_descriptor(error, 'message'); // if the message was already changed and it's not configurable we can't change it @@ -78,17 +78,28 @@ function adjust_error(error, effect) { context = context.p; } - define_property(error, 'message', { - value: error.message + `\n${component_stack}\n` - }); + return { + message: error.message + `\n${component_stack}\n`, + stack: error.stack + ?.split('\n') + .filter((line) => !line.includes('svelte/src/internal')) + .join('\n') + }; +} + +/** + * @param {Error} error + */ +function apply_adjustments(error) { + const adjusted = adjustments.get(error); + + if (adjusted) { + define_property(error, 'message', { + value: adjusted.message + }); - if (error.stack) { - // Filter out internal modules define_property(error, 'stack', { - value: error.stack - .split('\n') - .filter((line) => !line.includes('svelte/src/internal')) - .join('\n') + value: adjusted.stack }); } } diff --git a/packages/svelte/tests/runtime-runes/samples/error-boundary-3/_config.js b/packages/svelte/tests/runtime-runes/samples/error-boundary-3/_config.js index 040e13676e..06da8f667c 100644 --- a/packages/svelte/tests/runtime-runes/samples/error-boundary-3/_config.js +++ b/packages/svelte/tests/runtime-runes/samples/error-boundary-3/_config.js @@ -9,6 +9,6 @@ export default test({ flushSync(); assert.deepEqual(logs, ['error caught']); - assert.htmlEqual(target.innerHTML, `
Fallback!
`); + assert.htmlEqual(target.innerHTML, `
oh no!
`); } }); diff --git a/packages/svelte/tests/runtime-runes/samples/error-boundary-3/main.svelte b/packages/svelte/tests/runtime-runes/samples/error-boundary-3/main.svelte index bad84666c0..bc7fe072c4 100644 --- a/packages/svelte/tests/runtime-runes/samples/error-boundary-3/main.svelte +++ b/packages/svelte/tests/runtime-runes/samples/error-boundary-3/main.svelte @@ -1,6 +1,6 @@