diff --git a/packages/svelte/src/internal/client/reactivity/sources.js b/packages/svelte/src/internal/client/reactivity/sources.js
index c2512d0d40..6fe837ff12 100644
--- a/packages/svelte/src/internal/client/reactivity/sources.js
+++ b/packages/svelte/src/internal/client/reactivity/sources.js
@@ -27,7 +27,8 @@ import {
UNOWNED,
MAYBE_DIRTY,
BLOCK_EFFECT,
- ROOT_EFFECT
+ ROOT_EFFECT,
+ PROXY_ONCHANGE_SYMBOL
} from '../constants.js';
import * as e from '../errors.js';
import { legacy_mode_flag, tracing_mode_flag } from '../../flags/index.js';
@@ -239,6 +240,14 @@ export function internal_set(source, value) {
if (!source.equals(value)) {
var old_value = source.v;
+ if (old_value != null && source.o?.onchange) {
+ // @ts-ignore
+ const remove = old_value[PROXY_ONCHANGE_SYMBOL];
+ if (remove && typeof remove === 'function') {
+ remove(source.o?.onchange, true);
+ }
+ }
+
if (is_destroying_effect) {
old_values.set(source, value);
} else {
diff --git a/packages/svelte/tests/runtime-runes/samples/state-onchange-reassign-proxy/_config.js b/packages/svelte/tests/runtime-runes/samples/state-onchange-reassign-proxy/_config.js
new file mode 100644
index 0000000000..92ddd1369d
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/state-onchange-reassign-proxy/_config.js
@@ -0,0 +1,30 @@
+import { flushSync } from 'svelte';
+import { test } from '../../test';
+
+export default test({
+ async test({ assert, target, logs }) {
+ const [btn, btn2, btn3, btn4] = target.querySelectorAll('button');
+
+ flushSync(() => {
+ btn.click();
+ });
+ assert.deepEqual(logs, ['a']);
+
+ flushSync(() => {
+ btn2.click();
+ });
+ assert.deepEqual(logs, ['a', 'b', 'c']);
+ flushSync(() => {
+ btn3.click();
+ });
+ assert.deepEqual(logs, ['a', 'b', 'c', 'b', 'c']);
+ flushSync(() => {
+ btn4.click();
+ });
+ assert.deepEqual(logs, ['a', 'b', 'c', 'b', 'c', 'c']);
+ flushSync(() => {
+ btn2.click();
+ });
+ assert.deepEqual(logs, ['a', 'b', 'c', 'b', 'c', 'c', 'b']);
+ }
+});
diff --git a/packages/svelte/tests/runtime-runes/samples/state-onchange-reassign-proxy/main.svelte b/packages/svelte/tests/runtime-runes/samples/state-onchange-reassign-proxy/main.svelte
new file mode 100644
index 0000000000..d1931cbaac
--- /dev/null
+++ b/packages/svelte/tests/runtime-runes/samples/state-onchange-reassign-proxy/main.svelte
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
\ No newline at end of file