Describe the bug
[following is created by Opus 4.7, hope that's fine, feel free to remove and/or request more info]
After upgrading from 5.55.2 to 5.55.3, a document-level click handler that calls store.set([]) no longer clears items rendered by a sibling {#each $store as item} block. The store write executes (verified by store.subscribe logging and by later reads), but the {#each} doesn't re-render, so the previously rendered DOM nodes stay visible.
Identical code is fine on 5.55.2, broken on 5.55.3, nothing else changed.
Bisect
5.25.8 ✓ → 5.40.0 ✓ → 5.47.0 ✓ → 5.51.0 ✓ → 5.53.0 ✓ → 5.54.0 ✓ → 5.55.0 ✓ → 5.55.2 ✓ → 5.55.3 ✗ → 5.55.4 ✗ → 5.55.5 ✗
Candidate from the 5.55.3 notes: fix: freeze deriveds once their containing effects are destroyed (#17921). Unconfirmed.
Abstract pattern
// store.ts
import { writable } from 'svelte/store'
export const items = writable<string[]>([])
<!-- Renderer.svelte -->
<script lang="ts">
import { items } from './store'
</script>
{#each $items as item}
<div class="item-marker">{item}</div>
{/each}
<!-- Listener.svelte -->
<script lang="ts">
import { onMount } from 'svelte'
import { items } from './store'
onMount(() => {
document.addEventListener('click', (event) => {
const el = event.target as Element
if (!el.closest('.item-marker')) {
items.set([]) // executes on 5.55.3, but {#each} does not update
}
})
})
</script>
Reproduction
Reduction attempts (what does NOT reproduce)
I attempted to reduce this to a standalone Svelte Playground example on 5.55.3. The minimal pattern above works correctly in the Playground. I also tried these additions, all of which still worked correctly on 5.55.3:
- Plain {#each} with text content
- {#each} with in:fly|global + out:fly|global transitions
- {#each} rendering a dynamic component via <item.component /> where the component internally uses $state and $derived
So the reduction surfaces a narrower picture: the bug needs something more than (document listener + store.set([]) + {#each $store}). The real application where this reproduces runs under SvelteKit with several nested wrapper components (four layers deep, each with their own effects and deriveds). I don't yet know which specific ingredient tips the balance.
What I've ruled out in the real app
- Not a listener-attachment issue — the handler fires and items.set([]) executes (confirmed via store.subscribe).
- Not an intermediate $derived($store) wrapper — removing one did not restore the behavior.
- Not HMR — reproduces on production builds.
- Not browser-specific.
Logs
System Info
svelte: 5.55.3 → 5.55.5 all broken; 5.55.2 last known good
node: 22.x
OS: Linux
Browser: Chrome (latest stable)
Severity
annoyance, 5.55.2 pin is a workaround. Happy to help further reduce this with maintainer guidance — it'll likely need someone familiar with the internal changes in 5.55.3 to point at which additional ingredient is the trigger.
Describe the bug
[following is created by Opus 4.7, hope that's fine, feel free to remove and/or request more info]
After upgrading from 5.55.2 to 5.55.3, a document-level click handler that calls store.set([]) no longer clears items rendered by a sibling {#each $store as item} block. The store write executes (verified by store.subscribe logging and by later reads), but the {#each} doesn't re-render, so the previously rendered DOM nodes stay visible.
Identical code is fine on 5.55.2, broken on 5.55.3, nothing else changed.
Bisect
5.25.8 ✓ → 5.40.0 ✓ → 5.47.0 ✓ → 5.51.0 ✓ → 5.53.0 ✓ → 5.54.0 ✓ → 5.55.0 ✓ → 5.55.2 ✓ → 5.55.3 ✗ → 5.55.4 ✗ → 5.55.5 ✗
Candidate from the 5.55.3 notes: fix: freeze deriveds once their containing effects are destroyed (#17921). Unconfirmed.
Abstract pattern
// store.ts import { writable } from 'svelte/store' export const items = writable<string[]>([]) <!-- Renderer.svelte --> <script lang="ts"> import { items } from './store' </script> {#each $items as item} <div class="item-marker">{item}</div> {/each} <!-- Listener.svelte --> <script lang="ts"> import { onMount } from 'svelte' import { items } from './store' onMount(() => { document.addEventListener('click', (event) => { const el = event.target as Element if (!el.closest('.item-marker')) { items.set([]) // executes on 5.55.3, but {#each} does not update } }) }) </script>Reproduction
Reduction attempts (what does NOT reproduce)
I attempted to reduce this to a standalone Svelte Playground example on 5.55.3. The minimal pattern above works correctly in the Playground. I also tried these additions, all of which still worked correctly on 5.55.3:
So the reduction surfaces a narrower picture: the bug needs something more than (document listener + store.set([]) + {#each $store}). The real application where this reproduces runs under SvelteKit with several nested wrapper components (four layers deep, each with their own effects and deriveds). I don't yet know which specific ingredient tips the balance.
What I've ruled out in the real app
Logs
System Info
svelte: 5.55.3 → 5.55.5 all broken; 5.55.2 last known good node: 22.x OS: Linux Browser: Chrome (latest stable)Severity
annoyance, 5.55.2 pin is a workaround. Happy to help further reduce this with maintainer guidance — it'll likely need someone familiar with the internal changes in 5.55.3 to point at which additional ingredient is the trigger.