svelte 5 throws state_unsafe_mutation when i set a count inside $derived Svelte
Svelte 5.20-ish. I have a filtered list and I wanted a count of what survived the filter, so:
let items = $state([]);
let visibleCount = $state(0);
let visible = $derived.by(() => {
const out = items.filter(i => i.active);
visibleCount = out.length;
return out;
});
Dev server dies with state_unsafe_mutation: Updating state inside a derived or template expression is forbidden.
I understand that it's forbidden. I don't understand why. In Svelte 4 this was a reactive statement and it just worked. What's the actual replacement pattern for deriving two things from one computation?
@muslin_mira · 4w ago · 3 replies
Replacement is: stop having two sources of truth, derive both.
That's the whole thing. Deriveds are memoised, so deriving from a derived doesn't re-run the filter.
Why it's forbidden: deriveds in Svelte 5 are pull-based. They run when something reads them, which might be twice, might be never if the component isn't rendering. If a derived writes state, the value of that state depends on whether anything happened to read the derived. That's how you get a bug that only reproduces when a panel is collapsed. Svelte 4's
$:had exactly that class of bug, it just never told you about it.Reply
Report
@tomato_tobin · 4w ago
'Depends on whether anything read it' — ok, that lands. I'd been thinking of $derived as 'runs when deps change' and it's actually 'runs when someone asks'.
Reply
Report
@muslin_mira · 4w ago
Right. And if you genuinely need a side effect when something changes, that's
$effect, and you should feel mildly guilty every time you write one.Reply
Report