fix: don't show adjusted error messages in boundaries (#16360)

pull/16361/head
Rich Harris 2 months ago committed by GitHub
parent 4ef53a75a9
commit a23599a196
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,5 @@
---
'svelte': patch
---
fix: don't show adjusted error messages in boundaries

@ -7,14 +7,16 @@ import { BOUNDARY_EFFECT, EFFECT_RAN } from './constants.js';
import { define_property, get_descriptor } from '../shared/utils.js'; import { define_property, get_descriptor } from '../shared/utils.js';
import { active_effect } from './runtime.js'; import { active_effect } from './runtime.js';
const adjustments = new WeakMap();
/** /**
* @param {unknown} error * @param {unknown} error
*/ */
export function handle_error(error) { export function handle_error(error) {
var effect = /** @type {Effect} */ (active_effect); var effect = /** @type {Effect} */ (active_effect);
if (DEV && error instanceof Error) { if (DEV && error instanceof Error && !adjustments.has(error)) {
adjust_error(error, effect); adjustments.set(error, get_adjustments(error, effect));
} }
if ((effect.f & EFFECT_RAN) === 0) { if ((effect.f & EFFECT_RAN) === 0) {
@ -48,21 +50,19 @@ export function invoke_error_boundary(error, effect) {
effect = effect.parent; effect = effect.parent;
} }
if (error instanceof Error) {
apply_adjustments(error);
}
throw error; throw error;
} }
/** @type {WeakSet<Error>} */
const adjusted_errors = new WeakSet();
/** /**
* Add useful information to the error message/stack in development * Add useful information to the error message/stack in development
* @param {Error} error * @param {Error} error
* @param {Effect} effect * @param {Effect} effect
*/ */
function adjust_error(error, effect) { function get_adjustments(error, effect) {
if (adjusted_errors.has(error)) return;
adjusted_errors.add(error);
const message_descriptor = get_descriptor(error, 'message'); const message_descriptor = get_descriptor(error, 'message');
// if the message was already changed and it's not configurable we can't change it // 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; context = context.p;
} }
define_property(error, 'message', { return {
value: error.message + `\n${component_stack}\n` 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', { define_property(error, 'stack', {
value: error.stack value: adjusted.stack
.split('\n')
.filter((line) => !line.includes('svelte/src/internal'))
.join('\n')
}); });
} }
} }

@ -9,6 +9,6 @@ export default test({
flushSync(); flushSync();
assert.deepEqual(logs, ['error caught']); assert.deepEqual(logs, ['error caught']);
assert.htmlEqual(target.innerHTML, `<div>Fallback!</div><button>+</button>`); assert.htmlEqual(target.innerHTML, `<div>oh no!</div><button>+</button>`);
} }
}); });

@ -1,6 +1,6 @@
<script> <script>
function throw_error() { function throw_error() {
throw new Error('test') throw new Error('oh no!')
} }
let count = $state(0); let count = $state(0);
@ -9,8 +9,8 @@
<svelte:boundary onerror={(e) => console.log('error caught')}> <svelte:boundary onerror={(e) => console.log('error caught')}>
{count > 0 ? throw_error() : null} {count > 0 ? throw_error() : null}
{#snippet failed()} {#snippet failed(e)}
<div>Fallback!</div> <div>{e.message}</div>
{/snippet} {/snippet}
</svelte:boundary> </svelte:boundary>

Loading…
Cancel
Save