sveltejs/svelte · warning · MigrationError
can't migrate `${...}` to `$${rune}` because there's a varia
Error message
can't migrate `${...}` to `$${rune}` because there's a variable named ${rune}.
Rename the variable and try again or migrate by hand. What it means
Thrown by the reactive-declaration migrator when converting a `let` declaration into `$state`/`$derived` would collide with an in-scope variable already named `state` or `derived`. Same shape as the props-rune collision (error 1) but for the instance-script state transform. The offending source slice is included in the message via `state.str.original.substring(...)`.
Source
Thrown at packages/svelte/src/compiler/migrate/index.js:717
);
}
}
} else {
state.props_insertion_point = /** @type {number} */ (declarator.end);
}
state.str.update(start, end, '');
continue;
}
/**
* @param {"state"|"derived"} rune
*/
function check_rune_binding(rune) {
const has_rune_binding = !!state.scope.get(rune);
if (has_rune_binding) {
throw new MigrationError(
`can't migrate \`${state.str.original.substring(/** @type {number} */ (node.start), node.end)}\` to \`$${rune}\` because there's a variable named ${rune}.\n Rename the variable and try again or migrate by hand.`
);
}
}
// state
if (declarator.init) {
let { start, end } = /** @type {{ start: number, end: number }} */ (declarator.init);
if (declarator.init.type === 'SequenceExpression') {
while (state.str.original[start] !== '(') start -= 1;
while (state.str.original[end - 1] !== ')') end += 1;
}
check_rune_binding('state');
state.str.prependLeft(start, '$state(');
state.str.appendRight(end, ')');View on GitHub (pinned to 20b341f100)
Solutions
- Rename the offending `state`/`derived` variable to something else (e.g. `currentState`, `memo`) and re-run migrate.
- Migrate the file by hand and apply runes directly without renaming.
- Pre-scan for `\b(state|derived)\b` declarations before running the codemod.
Example fix
// before <script> let state = $: computeInitial(); let count = 0; $: doubled = count * 2; </script> // after (rename, then migrate) <script> let currentState = computeInitial(); let count = $state(0); let doubled = $derived(count * 2); </script>
Defensive patterns
Strategy: validation
Validate before calling
// Detect instance-script state/derived identifier collisions.
function hasStateNameCollision(source) {
const script = source.match(/<script\b[^>]*>([\s\S]*?)<\/script>/)?.[1] ?? '';
return /\b(let|const|var)\s+(state|derived)\b/.test(script);
}
if (hasStateNameCollision(componentSource)) {
// rename before migrating
} Try / catch
const { code } = migrate({ filename, source });
if (code.startsWith('<!-- @migration-task') && /because there's a variable named (state|derived)/i.test(code)) {
// rename the offending variable and re-run, or hand-migrate
} Prevention
- Reserve the names `state` and `derived` for runes in Svelte 5 code.
- Avoid `let state`/`let derived` in Svelte 4 components destined for migration.
- Run a naming-collision grep before each migrate batch.
When it happens
Trigger: Running `migrate()` on a Svelte 4 component whose `<script>` declares `let state = ...` or `let derived = ...` (or otherwise introduces such a binding into the component scope), and the codemod needs to emit `$state(...)` or `$derived(...)` for another declaration.
Common situations: State-machine or XState-style components where `state` is a natural variable name; computed-cache components that name a memo `derived`. The collision is purely lexical — the rune name clashes with the user identifier.
Related errors
- migrating this component would require adding a `$${rune}` r
- can't migrate `: ${...}` to `$${rune}` because there's a var
- This migration would change the name of a slot (${slot_name}
- This migration would change the name of a slot (${name} to $
- Can't migrate code with ${illegal_specifiers.join(' and ')}.
AI-assisted analysis of sveltejs/svelte@20b341f100 (2026-08-12).
Data as JSON: /api/errors/5c8e572a916be686.
Report an issue: GitHub.