diff --git a/.changeset/rich-emus-study.md b/.changeset/rich-emus-study.md
new file mode 100644
index 000000000000..dcadafacb19b
--- /dev/null
+++ b/.changeset/rich-emus-study.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: ensure sources within nested effects still register correctly
diff --git a/packages/svelte/src/internal/client/proxy.js b/packages/svelte/src/internal/client/proxy.js
index 60eba6aa8708..d9063aee3436 100644
--- a/packages/svelte/src/internal/client/proxy.js
+++ b/packages/svelte/src/internal/client/proxy.js
@@ -44,6 +44,7 @@ export function proxy(value) {
 	var reaction = active_reaction;
 
 	/**
+	 * Executes the proxy in the context of the reaction it was originally created in, if any
 	 * @template T
 	 * @param {() => T} fn
 	 */
diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js
index 56f41382520a..4959bc1abc85 100644
--- a/packages/svelte/src/internal/client/reactivity/sources.js
+++ b/packages/svelte/src/internal/client/reactivity/sources.js
@@ -138,7 +138,7 @@ export function set(source, value, should_proxy = false) {
 		!untracking &&
 		is_runes() &&
 		(active_reaction.f & (DERIVED | BLOCK_EFFECT)) !== 0 &&
-		!reaction_sources?.includes(source)
+		!(reaction_sources?.[1].includes(source) && reaction_sources[0] === active_reaction)
 	) {
 		e.state_unsafe_mutation();
 	}
diff --git a/packages/svelte/src/internal/client/runtime.js b/packages/svelte/src/internal/client/runtime.js
index 954406095904..56bc157f33cf 100644
--- a/packages/svelte/src/internal/client/runtime.js
+++ b/packages/svelte/src/internal/client/runtime.js
@@ -84,8 +84,8 @@ export function set_active_effect(effect) {
 
 /**
  * When sources are created within a reaction, reading and writing
- * them should not cause a re-run
- * @type {null | Source[]}
+ * them within that reaction should not cause a re-run
+ * @type {null | [active_reaction: Reaction, sources: Source[]]}
  */
 export let reaction_sources = null;
 
@@ -93,9 +93,9 @@ export let reaction_sources = null;
 export function push_reaction_value(value) {
 	if (active_reaction !== null && active_reaction.f & EFFECT_IS_UPDATING) {
 		if (reaction_sources === null) {
-			reaction_sources = [value];
+			reaction_sources = [active_reaction, [value]];
 		} else {
-			reaction_sources.push(value);
+			reaction_sources[1].push(value);
 		}
 	}
 }
@@ -234,7 +234,7 @@ function schedule_possible_effect_self_invalidation(signal, effect, root = true)
 	for (var i = 0; i < reactions.length; i++) {
 		var reaction = reactions[i];
 
-		if (reaction_sources?.includes(signal)) continue;
+		if (reaction_sources?.[1].includes(signal) && reaction_sources[0] === active_reaction) continue;
 
 		if ((reaction.f & DERIVED) !== 0) {
 			schedule_possible_effect_self_invalidation(/** @type {Derived} */ (reaction), effect, false);
@@ -724,7 +724,7 @@ export function get(signal) {
 
 	// Register the dependency on the current reaction signal.
 	if (active_reaction !== null && !untracking) {
-		if (!reaction_sources?.includes(signal)) {
+		if (!reaction_sources?.[1].includes(signal) || reaction_sources[0] !== active_reaction) {
 			var deps = active_reaction.deps;
 			if (signal.rv < read_version) {
 				signal.rv = read_version;
diff --git a/packages/svelte/tests/signals/test.ts b/packages/svelte/tests/signals/test.ts
index 8421ae4a7cbf..78d7919e0fb1 100644
--- a/packages/svelte/tests/signals/test.ts
+++ b/packages/svelte/tests/signals/test.ts
@@ -1021,6 +1021,41 @@ describe('signals', () => {
 		};
 	});
 
+	test('nested effects depend on state of upper effects', () => {
+		const logs: number[] = [];
+
+		user_effect(() => {
+			const raw = state(0);
+			const proxied = proxy({ current: 0 });
+
+			// We need those separate, else one working and rerunning the effect
+			// could mask the other one not rerunning
+			user_effect(() => {
+				logs.push($.get(raw));
+			});
+
+			user_effect(() => {
+				logs.push(proxied.current);
+			});
+
+			// Important so that the updating effect is not running
+			// together with the reading effects
+			flushSync();
+
+			user_effect(() => {
+				$.untrack(() => {
+					set(raw, $.get(raw) + 1);
+					proxied.current += 1;
+				});
+			});
+		});
+
+		return () => {
+			flushSync();
+			assert.deepEqual(logs, [0, 0, 1, 1]);
+		};
+	});
+
 	test('proxy version state does not trigger self-dependency guard', () => {
 		return () => {
 			const s = proxy({ a: { b: 1 } });