fix: avoid writing to not writable error object in handle_error
In web workers, error objects aren't writable. So in that case, there's no point in trying to decorate the error.
🦋 Changeset detected
Latest commit: d4366ff4851ef1c67c4add0ca3454e0d64f3eb55
The changes in this PR will be included in the next version bump.
This PR includes changesets to release 1 package
| Name | Type |
|---|---|
| svelte | Patch |
Not sure what this means? Click here to learn what changesets are.
Click here if you're a maintainer who wants to add another changeset to this PR
I just ran into this locally while looking into something else and was able to solve it with Object.defineProperty — any reason not to use that instead?
Does that work for workers too?
The behaviour I see is quite strange. With a new Error('original message'):
- in Firefox and Safari overwriting the message works just fine
- in Chrome I can set the value, and it updates (
console.log(e.message)reflects the new value), but the error that's printed to the console contains the original message. Presumably something to do with how the error is cloned (though if I manuallystructuredClonethe error, it works)
The place where I originally saw this was with a DOMException (in the main thread), where the message is a getter on the prototype rather than a property of the error object:
try {
document.createComment('').appendChild(document.createElement('div'));
} catch (e) {
console.log(Object.getOwnPropertyDescriptor(e, 'message')); // undefined
e.message = 'overwritten'; // has no effect
console.log(e.message); // original message
Object.defineProperty(e, 'message', { value: 'overwritten' });
console.log(e.message); // 'overwritten'
throw e; // throws 'overwritten' in Chrome and Safari, original message in Firefox
}
So there's absolutely no consistency between browsers, they're all just making it up as they go along. I'm not sure how to create a DOMException in a worker where there's no DOM; things like SyntaxError which I imagined would be similar are actually more like conventional errors.
In other words I can't answer your question without knowing what error you were dealing with in the first place, because normal errors seem to work just fine (except that the overwritten message is ignored in some situations).
I switched to using Object.assign
did you test this with the error you encountered with a non-writable message?
@Rich-Harris I'll try and find out from the user who reported it.
It doesn't seem to be fixed. I created a laughably minimal repro. I guess the error is still thrown by the worker, even though one might expect it to be thrown by the main thread...
Here is a something similar to what I had in my original code of the error in case its useful to have more substance.
EDIT: I notice for some reason the stack trace might not be showing in the REPL, even though the error does. Here is my local dev stack trace:
Uncaught (in promise) TypeError: Cannot set property message of which has only a getter
at handle_error (runtime.js:288:8)
at execute_effect (runtime.js:503:3)
at flush_queued_effects (runtime.js:568:4)
at flush_queued_root_effects (runtime.js:548:5)
at flush_sync (runtime.js:745:4)
at flush_sync (runtime.js:752:4)
at mount (render.js:106:9)
at new Svelte4Component (legacy-client.js:75:49)
at new <anonymous> (legacy-client.js:47:4)
at initialize (client.js:434:9)
runtime.js 287-290
const indent = /Firefox/.test(navigator.userAgent) ? ' ' : '\t';
error.message += `\n${component_stack.map((name) => `\n${indent}in ${name}`).join('')}\n`;
^^^^^^^
const stack = error.stack;
Seems to be fixed just fine? Here's the second example running on this branch