diff --git a/.changeset/nice-pianos-punch.md b/.changeset/nice-pianos-punch.md
new file mode 100644
index 0000000000..f70af9eb04
--- /dev/null
+++ b/.changeset/nice-pianos-punch.md
@@ -0,0 +1,5 @@
+---
+'svelte': patch
+---
+
+fix: prevent state runes from being called with spread
diff --git a/documentation/docs/98-reference/.generated/compile-errors.md b/documentation/docs/98-reference/.generated/compile-errors.md
index ea116014e7..a8c39aaf97 100644
--- a/documentation/docs/98-reference/.generated/compile-errors.md
+++ b/documentation/docs/98-reference/.generated/compile-errors.md
@@ -660,6 +660,12 @@ Cannot access a computed property of a rune
`%name%` is not a valid rune
```
+### rune_invalid_spread
+
+```
+`%rune%` cannot be called with a spread argument
+```
+
### rune_invalid_usage
```
diff --git a/packages/svelte/CHANGELOG.md b/packages/svelte/CHANGELOG.md
index 4bac129169..86e1179029 100644
--- a/packages/svelte/CHANGELOG.md
+++ b/packages/svelte/CHANGELOG.md
@@ -1,5 +1,17 @@
# svelte
+## 5.25.2
+
+### Patch Changes
+
+- feat: migrate reassigned deriveds to `$derived` ([#15581](https://github.com/sveltejs/svelte/pull/15581))
+
+## 5.25.1
+
+### Patch Changes
+
+- fix: prevent dev server from throwing errors when attempting to retrieve the proxied value of an iframe's contentWindow ([#15577](https://github.com/sveltejs/svelte/pull/15577))
+
## 5.25.0
### Minor Changes
diff --git a/packages/svelte/messages/compile-errors/script.md b/packages/svelte/messages/compile-errors/script.md
index 795c0b007d..aabcbeae48 100644
--- a/packages/svelte/messages/compile-errors/script.md
+++ b/packages/svelte/messages/compile-errors/script.md
@@ -162,6 +162,10 @@ This turned out to be buggy and unpredictable, particularly when working with de
> `%name%` is not a valid rune
+## rune_invalid_spread
+
+> `%rune%` cannot be called with a spread argument
+
## rune_invalid_usage
> Cannot use `%rune%` rune in non-runes mode
diff --git a/packages/svelte/package.json b/packages/svelte/package.json
index e3824b89fb..56fa949391 100644
--- a/packages/svelte/package.json
+++ b/packages/svelte/package.json
@@ -2,7 +2,7 @@
"name": "svelte",
"description": "Cybernetically enhanced web apps",
"license": "MIT",
- "version": "5.25.0",
+ "version": "5.25.2",
"type": "module",
"types": "./types/index.d.ts",
"engines": {
diff --git a/packages/svelte/src/compiler/errors.js b/packages/svelte/src/compiler/errors.js
index 677b99fcff..6bf973948b 100644
--- a/packages/svelte/src/compiler/errors.js
+++ b/packages/svelte/src/compiler/errors.js
@@ -383,6 +383,16 @@ export function rune_invalid_name(node, name) {
e(node, 'rune_invalid_name', `\`${name}\` is not a valid rune\nhttps://svelte.dev/e/rune_invalid_name`);
}
+/**
+ * `%rune%` cannot be called with a spread argument
+ * @param {null | number | NodeLike} node
+ * @param {string} rune
+ * @returns {never}
+ */
+export function rune_invalid_spread(node, rune) {
+ e(node, 'rune_invalid_spread', `\`${rune}\` cannot be called with a spread argument\nhttps://svelte.dev/e/rune_invalid_spread`);
+}
+
/**
* Cannot use `%rune%` rune in non-runes mode
* @param {null | number | NodeLike} node
diff --git a/packages/svelte/src/compiler/migrate/index.js b/packages/svelte/src/compiler/migrate/index.js
index 7f26d0d010..9d79d88b23 100644
--- a/packages/svelte/src/compiler/migrate/index.js
+++ b/packages/svelte/src/compiler/migrate/index.js
@@ -952,7 +952,7 @@ const instance_script = {
const reassigned_bindings = bindings.filter((b) => b?.reassigned);
if (
- reassigned_bindings.length === 0 &&
+ node.body.expression.right.type !== 'Literal' &&
!bindings.some((b) => b?.kind === 'store_sub') &&
node.body.expression.left.type !== 'MemberExpression'
) {
diff --git a/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js b/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js
index a9ee96257a..e58bf5bb69 100644
--- a/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js
+++ b/packages/svelte/src/compiler/phases/2-analyze/visitors/CallExpression.js
@@ -17,6 +17,14 @@ export function CallExpression(node, context) {
const rune = get_rune(node, context.state.scope);
+ if (rune && rune !== '$inspect') {
+ for (const arg of node.arguments) {
+ if (arg.type === 'SpreadElement') {
+ e.rune_invalid_spread(node, rune);
+ }
+ }
+ }
+
switch (rune) {
case null:
if (!is_safe_identifier(node.callee, context.state.scope)) {
diff --git a/packages/svelte/src/internal/client/proxy.js b/packages/svelte/src/internal/client/proxy.js
index 3f6d5490d3..6efbfe2cbd 100644
--- a/packages/svelte/src/internal/client/proxy.js
+++ b/packages/svelte/src/internal/client/proxy.js
@@ -462,8 +462,18 @@ function update_version(signal, d = 1) {
* @param {any} value
*/
export function get_proxied_value(value) {
- if (value !== null && typeof value === 'object' && STATE_SYMBOL in value) {
- return value[STATE_SYMBOL];
+ try {
+ if (value !== null && typeof value === 'object' && STATE_SYMBOL in value) {
+ return value[STATE_SYMBOL];
+ }
+ } catch {
+ // the above if check can throw an error if the value in question
+ // is the contentWindow of an iframe on another domain, in which
+ // case we want to just return the value (because it's definitely
+ // not a proxied value) so we don't break any JavaScript interacting
+ // with that iframe (such as various payment companies client side
+ // JavaScript libraries interacting with their iframes on the same
+ // domain)
}
return value;
diff --git a/packages/svelte/src/version.js b/packages/svelte/src/version.js
index a62190bb2e..e2dc6c2c09 100644
--- a/packages/svelte/src/version.js
+++ b/packages/svelte/src/version.js
@@ -4,5 +4,5 @@
* The current version, as set in package.json.
* @type {string}
*/
-export const VERSION = '5.25.0';
+export const VERSION = '5.25.2';
export const PUBLIC_VERSION = '5';
diff --git a/packages/svelte/tests/migrate/samples/reassigned-deriveds/input.svelte b/packages/svelte/tests/migrate/samples/reassigned-deriveds/input.svelte
new file mode 100644
index 0000000000..024f719fb9
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/reassigned-deriveds/input.svelte
@@ -0,0 +1,10 @@
+
+
+
+
+
+{upper}
\ No newline at end of file
diff --git a/packages/svelte/tests/migrate/samples/reassigned-deriveds/output.svelte b/packages/svelte/tests/migrate/samples/reassigned-deriveds/output.svelte
new file mode 100644
index 0000000000..0903299d95
--- /dev/null
+++ b/packages/svelte/tests/migrate/samples/reassigned-deriveds/output.svelte
@@ -0,0 +1,10 @@
+
+
+
+
+
+{upper}
\ No newline at end of file
diff --git a/packages/svelte/tests/validator/samples/rune-invalid-spread-derived-by/errors.json b/packages/svelte/tests/validator/samples/rune-invalid-spread-derived-by/errors.json
new file mode 100644
index 0000000000..be59da95fa
--- /dev/null
+++ b/packages/svelte/tests/validator/samples/rune-invalid-spread-derived-by/errors.json
@@ -0,0 +1,14 @@
+[
+ {
+ "code": "rune_invalid_spread",
+ "end": {
+ "column": 35,
+ "line": 3
+ },
+ "message": "`$derived.by` cannot be called with a spread argument",
+ "start": {
+ "column": 15,
+ "line": 3
+ }
+ }
+]
diff --git a/packages/svelte/tests/validator/samples/rune-invalid-spread-derived-by/input.svelte b/packages/svelte/tests/validator/samples/rune-invalid-spread-derived-by/input.svelte
new file mode 100644
index 0000000000..49e8057aa5
--- /dev/null
+++ b/packages/svelte/tests/validator/samples/rune-invalid-spread-derived-by/input.svelte
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/packages/svelte/tests/validator/samples/rune-invalid-spread-derived/errors.json b/packages/svelte/tests/validator/samples/rune-invalid-spread-derived/errors.json
new file mode 100644
index 0000000000..6a333bc362
--- /dev/null
+++ b/packages/svelte/tests/validator/samples/rune-invalid-spread-derived/errors.json
@@ -0,0 +1,14 @@
+[
+ {
+ "code": "rune_invalid_spread",
+ "end": {
+ "column": 32,
+ "line": 3
+ },
+ "message": "`$derived` cannot be called with a spread argument",
+ "start": {
+ "column": 15,
+ "line": 3
+ }
+ }
+]
diff --git a/packages/svelte/tests/validator/samples/rune-invalid-spread-derived/input.svelte b/packages/svelte/tests/validator/samples/rune-invalid-spread-derived/input.svelte
new file mode 100644
index 0000000000..9155493e17
--- /dev/null
+++ b/packages/svelte/tests/validator/samples/rune-invalid-spread-derived/input.svelte
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/packages/svelte/tests/validator/samples/rune-invalid-spread-state-raw/errors.json b/packages/svelte/tests/validator/samples/rune-invalid-spread-state-raw/errors.json
new file mode 100644
index 0000000000..e08b498fcb
--- /dev/null
+++ b/packages/svelte/tests/validator/samples/rune-invalid-spread-state-raw/errors.json
@@ -0,0 +1,14 @@
+[
+ {
+ "code": "rune_invalid_spread",
+ "end": {
+ "column": 34,
+ "line": 3
+ },
+ "message": "`$state.raw` cannot be called with a spread argument",
+ "start": {
+ "column": 15,
+ "line": 3
+ }
+ }
+]
diff --git a/packages/svelte/tests/validator/samples/rune-invalid-spread-state-raw/input.svelte b/packages/svelte/tests/validator/samples/rune-invalid-spread-state-raw/input.svelte
new file mode 100644
index 0000000000..d06fb053b3
--- /dev/null
+++ b/packages/svelte/tests/validator/samples/rune-invalid-spread-state-raw/input.svelte
@@ -0,0 +1,4 @@
+
\ No newline at end of file
diff --git a/packages/svelte/tests/validator/samples/rune-invalid-spread-state/errors.json b/packages/svelte/tests/validator/samples/rune-invalid-spread-state/errors.json
new file mode 100644
index 0000000000..11ae2abce5
--- /dev/null
+++ b/packages/svelte/tests/validator/samples/rune-invalid-spread-state/errors.json
@@ -0,0 +1,14 @@
+[
+ {
+ "code": "rune_invalid_spread",
+ "end": {
+ "column": 30,
+ "line": 3
+ },
+ "message": "`$state` cannot be called with a spread argument",
+ "start": {
+ "column": 15,
+ "line": 3
+ }
+ }
+]
diff --git a/packages/svelte/tests/validator/samples/rune-invalid-spread-state/input.svelte b/packages/svelte/tests/validator/samples/rune-invalid-spread-state/input.svelte
new file mode 100644
index 0000000000..02feac893f
--- /dev/null
+++ b/packages/svelte/tests/validator/samples/rune-invalid-spread-state/input.svelte
@@ -0,0 +1,4 @@
+
\ No newline at end of file