-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Closed
Closed
Copy link
Description
Describe the bug
I found big inconsistencies in when/if the state_unsafe_mutation
warning/error is shown.
This is the setup:
<script>
class State {
_x = $state(null)
get_x() {
if (this._x === null) {
this._x = 5
}
return this._x
}
get x() {
if (this._x === null) {
this._x = 5
}
return this._x
}
}
const s = new State()
// $inspect(s.get_x()) // makes a difference when uncommented
// $inspect(s.x) // makes a difference when uncommented
// $inspect(s._x) // does NOT make a difference when uncommented
</script>
<h1>Hello {s.get_x()}!</h1>
<h1>Hello {s.x}!</h1>
This results in the following error:
state_unsafe_mutation Updating state inside a derived or a template expression is forbidden. If the value should not be reactive, declare it without `$state` https://svelte.dev/e/state_unsafe_mutation in {expression} in App.svelte
However, if one of the top two $inspect
s is uncommented, the code passes and runs with the expected result.
If the bottom $inspect
is uncommented, the code fails and does not run, the above error is thrown.
Reproduction
https://svelte.dev/playground/686feb80ab0e41d29668232eacfdf8a4?version=5.34.2
Logs
System Info
playground
Severity
annoyance
Metadata
Metadata
Assignees
Labels
No labels
Type
Projects
Milestone
Relationships
Development
Select code repository
Activity
paoloricciuti commentedon Jun 14, 2025
This seems perfectly reasonable to me: inspect is invoked immediately which means the assignment doesn't happen in the template...if you access
_x
you are not writing to state so_x
is still null when you get to the template and it's written to.timephy commentedon Jun 14, 2025
I also have a related question: Is what I describe below "allowed"?
I got the error of this issue, when
loadDataAsync()
was cached and therefore ran the.then(...)
function, setting the$state
IMMEDIATELY.To solve for this I used
queueMicrotask(...)
→queueMicrotask(() => loadDataAsync().then(() => (this._x = "loaded")))
.So the eventual question is:
Can one safely use
queueMicrotask
inside a$derived
or template?timephy commentedon Jun 14, 2025
It does make sense! I agree.
But should it be like that?
imo it is misleading for
$inspect
to have "side-effects"...Especially when
$inspect(s.x)
has an influence on whether{s.get_x()}
errors or not![-]❗ Big inconsistencies with `state_unsafe_mutation`[/-][+]❗Inconsistencies of using `$inspect` resulting in `state_unsafe_mutation`[/+]paoloricciuti commentedon Jun 14, 2025
Oh yeah it should not have side effects but can we prevent that? Maybe we should error out if you set state in inspect too? 🤔
timephy commentedon Jun 14, 2025
I feel like that would make sense...
Should it make a difference from where you "observe"/"subscribe"? I guess not?
timephy commentedon Jun 14, 2025
So what about this? Is this allowed?
paoloricciuti commentedon Jun 14, 2025
It should be safe as in that case you are not really setting state in the derived
[-]❗Inconsistencies of using `$inspect` resulting in `state_unsafe_mutation`[/-][+]`$inspect` should cause `state_unsafe_mutation` when setting `$state` inside it[/+]$inspect.with
and add check for unsafe mutation #16209