diff --git a/.changeset/stupid-baboons-fall.md b/.changeset/stupid-baboons-fall.md
new file mode 100644
index 0000000000..66895ad015
--- /dev/null
+++ b/.changeset/stupid-baboons-fall.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: abort running obsolete async branches
diff --git a/packages/svelte/src/internal/client/reactivity/async.js b/packages/svelte/src/internal/client/reactivity/async.js
index 61fff31f8a..5e418d81a1 100644
--- a/packages/svelte/src/internal/client/reactivity/async.js
+++ b/packages/svelte/src/internal/client/reactivity/async.js
@@ -55,14 +55,16 @@ export function flatten(blockers, sync, async, fn) {
/** @param {Value[]} values */
function finish(values) {
+ if ((parent.f & DESTROYED) !== 0) {
+ return;
+ }
+
restore();
try {
fn(values);
} catch (error) {
- if ((parent.f & DESTROYED) === 0) {
- invoke_error_boundary(error, parent);
- }
+ invoke_error_boundary(error, parent);
}
unset_context();
diff --git a/packages/svelte/src/internal/client/reactivity/deriveds.js b/packages/svelte/src/internal/client/reactivity/deriveds.js
index eb934d96ff..070dfc8ff3 100644
--- a/packages/svelte/src/internal/client/reactivity/deriveds.js
+++ b/packages/svelte/src/internal/client/reactivity/deriveds.js
@@ -239,7 +239,7 @@ export function async_derived(fn, label, location) {
recent_async_deriveds.add(signal);
setTimeout(() => {
- if (recent_async_deriveds.has(signal)) {
+ if (recent_async_deriveds.has(signal) && (effect.f & DESTROYED) === 0) {
w.await_waterfall(/** @type {string} */ (signal.label), location);
recent_async_deriveds.delete(signal);
}
diff --git a/packages/svelte/tests/runtime-runes/samples/async-obsolete-branch-no-effect-runs/Child.svelte b/packages/svelte/tests/runtime-runes/samples/async-obsolete-branch-no-effect-runs/Child.svelte
new file mode 100644
index 0000000000..1d9bdfada2
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/async-obsolete-branch-no-effect-runs/Child.svelte
@@ -0,0 +1,6 @@
+
diff --git a/packages/svelte/tests/runtime-runes/samples/async-obsolete-branch-no-effect-runs/_config.js b/packages/svelte/tests/runtime-runes/samples/async-obsolete-branch-no-effect-runs/_config.js
new file mode 100644
index 0000000000..83364706e5
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/async-obsolete-branch-no-effect-runs/_config.js
@@ -0,0 +1,27 @@
+import { tick } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ async test({ assert, target, logs, warnings }) {
+ const [increment, resolve] = target.querySelectorAll('button');
+
+ increment.click();
+ await tick();
+ assert.deepEqual(logs, []);
+
+ resolve.click();
+ await tick();
+ assert.deepEqual(logs, []);
+
+ resolve.click();
+ await tick();
+ assert.deepEqual(logs, []);
+
+ resolve.click();
+ await tick();
+ assert.deepEqual(logs, [1, 2]);
+
+ // no await waterfall / inert derived warnings
+ assert.deepEqual(warnings, []);
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/async-obsolete-branch-no-effect-runs/main.svelte b/packages/svelte/tests/runtime-runes/samples/async-obsolete-branch-no-effect-runs/main.svelte
new file mode 100644
index 0000000000..fe01ae457e
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/async-obsolete-branch-no-effect-runs/main.svelte
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+ {#if count % 2 === 0}
+ {@const double = count * 2}
+ true
+ {await push(count)} {double}
+
+ {:else}
+ false
+
+ {/if}
+
+ {#snippet pending()}
+ loading...
+ {/snippet}
+