sveltejs/svelte · warning · MigrationError
Can't migrate code with ${illegal_specifiers.join(' and ')}.
Error message
Can't migrate code with ${illegal_specifiers.join(' and ')}. Please migrate by hand. What it means
Thrown by the migrate codemod when a `<script>` import statement contains specifiers the automigrator cannot safely rewrite or drop (tracked in `illegal_specifiers`). The remaining specifiers are joined into the message. It is caught by the migrate entry point and surfaced as a `<!-- @migration-task -->` comment in the returned source.
Source
Thrown at packages/svelte/src/compiler/migrate/index.js:538
state.str.original.indexOf(',', specifier.end) !== -1 &&
state.str.original.indexOf(',', specifier.end) <
state.str.original.indexOf('}', specifier.end)
? state.str.original.indexOf(',', specifier.end) + 1
: specifier.end
);
while (state.str.original[end].trim() === '') end++;
state.str.remove(/** @type {number} */ (specifier.start), end);
removed_specifiers++;
continue;
}
illegal_specifiers.push(specifier.imported.name);
}
}
if (removed_specifiers === node.specifiers.length) {
state.str.remove(/** @type {number} */ (node.start), /** @type {number} */ (node.end));
}
if (illegal_specifiers.length > 0) {
throw new MigrationError(
`Can't migrate code with ${illegal_specifiers.join(' and ')}. Please migrate by hand.`
);
}
}
},
ExportNamedDeclaration(node, { state, next }) {
if (node.declaration) {
next();
return;
}
let count_removed = 0;
for (const specifier of node.specifiers) {
if (specifier.local.type !== 'Identifier') continue;
const binding = state.scope.get(specifier.local.name);
if (binding?.kind === 'bindable_prop') {
state.str.remove(View on GitHub (pinned to 20b341f100)
Solutions
- Read the named specifiers in the error and manually rewrite that import in the component, then re-run migrate.
- Move the offending import into a plain `.js`/`.ts` module instead of a `<script context="module">` block.
- Migrate the affected file by hand and exclude it from the batch run.
Example fix
// before
<script context="module">
import { onMount, afterUpdate } from 'svelte';
</script>
// after (keep only what still applies; afterUpdate has no runes equivalent)
<script>
import { onMount } from 'svelte';
</script> Defensive patterns
Strategy: validation
Validate before calling
// Before migrating, scan module scripts for imports the codemod rejects.
function riskyModuleImports(source) {
const matches = source.match(/<script\s+context=["']module["'][\s\S]*?<\/script>/g) || [];
// flag re-exports of svelte lifecycle hooks or legacy helpers
return matches.some(s => /import\s*\{[^}]*(onMount|afterUpdate|beforeUpdate|onDestroy)/.test(s));
} Try / catch
const { code } = migrate({ filename, source });
if (/illegal|cannot be automatically migrated/i.test(code) && code.startsWith('<!-- @migration-task')) {
// open the file and rewrite the flagged import by hand
} Prevention
- Keep `svelte` imports in regular instance scripts, not `<script context="module">` blocks.
- Avoid re-exporting Svelte lifecycle functions from component module scripts.
- Inspect migrate output for `@migration-task` comments after each batch run.
When it happens
Trigger: Running `migrate()` on a component whose `<script context="module">` or instance script imports symbols that the Svelte 4→5 transform treats as illegal (typically lifecycle/hook re-exports or specifiers tied to APIs removed in runes mode). The visitor collects offending `specifier.imported.name` entries and throws once the import node is processed.
Common situations: Components that re-export Svelte 4 lifecycle functions (`onMount`, `afterUpdate`, etc.) from `svelte` in a module script, or that import helpers used only by legacy patterns the codemod rewrites away. Most often seen in shared utility/component libraries.
Related errors
- migrating this component would require adding a `$${rune}` r
- Encountered an export declaration pattern that is not suppor
- $$props is used together with named props in a way that cann
- can't migrate `${...}` to `$${rune}` because there's a varia
- can't migrate `: ${...}` to `$${rune}` because there's a var
AI-assisted analysis of sveltejs/svelte@20b341f100 (2026-08-12).
Data as JSON: /api/errors/da900525a83adbb5.
Report an issue: GitHub.