fix: re-evaluate derived props during teardown
#16278
Closing issues
Describe the bug
Not sure if this is a bug or intended. According to this breaking change, if the state caused an $effect to rerun, Svelte should provide the previous value of the state in the teardown function. This work for $state currently, but not for $derived, though it does work if $derived is reassigned.
Reproduction
Logs
System Info
Svelte playground (5.33.18)
Chrome 137.0.7151.56
Severity
annoyance
Describe the bug
When a prop has a setter (for instance <button onclick={() => (checked = !checked)}></button>) but it doesn't have a getter (like <p>{checked}</p>), the value read during onDestroy does not match either the old or the current value of the prop, it's instead read as null.
This happens because the compiler decides to use $.prop to read the prop since it detects a "setter", $.prop "wraps" the prop in a derived but since we never read from it, when we execute onDestroy the derived is still in an "uninitialized" state hence it returns null instead of the correct value.
Reproduction
https://svelte.dev/playground/4fa745c18a3c41e88bda761f37b36783?version=5.34.9
Click count++ twice, the 2nd time the Component is unmounted and onDestroy is called and it will log the incorrect checked value that should be true but is logged as null.
System Info
System:
OS: Windows 11 10.0.26100
CPU: (32) x64 Intel(R) Core(TM) i9-14900HX
Memory: 41.79 GB / 63.74 GB
Binaries:
Node: 23.5.0 - C:\Program Files\nodejs\node.EXE
Yarn: 1.22.22 - C:\Program Files\nodejs\yarn.CMD
npm: 11.0.0 - C:\Program Files\nodejs\npm.CMD
pnpm: 10.4.0 - ~\AppData\Local\pnpm\pnpm.CMD
Browsers:
Edge: Chromium (137.0.3296.93)
Internet Explorer: 11.0.26100.1882
Severity
annoyance
Pull request
alternative to #16263, made possible by #16270. Closes #16114, closes #16262
Before submitting the PR, please make sure you do the following
- It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
- Prefix your PR title with
feat:,fix:,chore:, ordocs:. - This message body should clearly illustrate what problems it solves.
- Ideally, include a test that fails without this PR but passes with it.
- If this PR changes code within
packages/svelte/src, add a changeset (npx changeset).
Tests and linting
- Run the tests with
pnpm testand lint the project withpnpm lint
Info
🦋 Changeset detected
Latest commit: cff7ed6
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
pnpm add https://pkg.pr.new/svelte@16278Even if there's a fix to be found for #16262 using the existing mechanism it won't fix the similar but different issue in #16072. I think we really need to widen the "keep last value on teardown" logic for props, or even make them their own signals, i.e. not pass them through but instead create "barriers" so the old value stays around.
what's the perf impact of these changes?
Negligible to non-existent — the only time there's any extra work at all is when reading deriveds in effect teardowns, which is rare, and it's only a tiny bit of extra work. pnpm bench:compare corroborates this
Add tests for props old values in onDestroy hooks to prevent regressions
• Jun 29, 2025, 3:46 PMremove extraneous tests - these pass with or without the src change
• Jun 30, 2025, 11:57 PMMerge branch 'gh-16263' of github.com:sveltejs/svelte into gh-16263
• Jul 1, 2025, 8:10 PM