sveltejs/svelte · warning · MigrationError
Encountered an export declaration pattern that is not suppor
Error message
Encountered an export declaration pattern that is not supported for automigration.
What it means
Thrown when an `export let` declaration uses a destructuring or non-Identifier pattern (e.g. `export let { x, y } = obj` or `export let [a, b] = arr`). The automigrator only knows how to convert simple Identifier exports into `$props()` bindings; turning destructuring into props is non-trivial because the leaves — not the pattern keys — are the prop names. The TODO comment in source confirms this is an intentionally unimplemented case.
Source
Thrown at packages/svelte/src/compiler/migrate/index.js:605
} catch (e) {
// no bindings, so we can skip this
next();
continue;
}
const has_state = bindings.some((binding) => binding.kind === 'state');
const has_props = bindings.some((binding) => binding.kind === 'bindable_prop');
if (!has_state && !has_props) {
next();
continue;
}
if (has_props) {
nr_of_props++;
if (declarator.id.type !== 'Identifier') {
// TODO invest time in this?
throw new MigrationError(
'Encountered an export declaration pattern that is not supported for automigration.'
);
// Turn export let into props. It's really really weird because export let { x: foo, z: [bar]} = ..
// means that foo and bar are the props (i.e. the leaves are the prop names), not x and z.
// const tmp = b.id(state.scope.generate('tmp'));
// const paths = extract_paths(declarator.id, tmp);
// state.props_pre.push(
// b.declaration('const', tmp, visit(declarator.init!) as Expression)
// );
// for (const path of paths) {
// const name = (path.node as Identifier).name;
// const binding = state.scope.get(name)!;
// const value = path.expression;
// if (binding.kind === 'bindable_prop' || binding.kind === 'rest_prop') {
// state.props.push({
// local: name,
// exported: binding.prop_alias ? binding.prop_alias : name,
// init: valueView on GitHub (pinned to 20b341f100)
Solutions
- Refactor the destructured `export let` into individual `export let` declarations (one per prop) before migrating.
- Migrate the file by hand using `let { theme = $bindable(), size = $bindable() } = $props()`.
- If the destructured source is a derived object (not the props bag), split the prop declarations from the destructuring.
Example fix
// before
<script>
export let { theme, size } = config;
</script>
// after (manual migration)
<script>
let { theme = $bindable(), size = $bindable() } = $props();
</script> Defensive patterns
Strategy: validation
Validate before calling
// Detect destructuring export-let patterns before invoking migrate.
function hasDestructuredExport(source) {
return /export\s+let\s*[\[\{]/.test(source);
}
if (hasDestructuredExport(componentSource)) {
// refactor to plain `export let x; export let y;` before migrating
} Try / catch
const { code } = migrate({ filename, source });
if (code.startsWith('<!-- @migration-task') && /export declaration pattern/i.test(code)) {
// hand-migrate the destructured export let to $props() with $bindable()
} Prevention
- Prefer individual `export let` declarations over destructured patterns in Svelte 4 components.
- When you need destructured config, keep it separate from exported props.
- Audit components for `export let {` / `export let [` before running the Svelte 5 migrator.
When it happens
Trigger: Running `migrate()` against a Svelte 4 component whose `<script>` contains `export let { ... } = ` or `export let [ ... ] = `, where at least one of the destructured bindings resolves to a bindable prop (`binding.kind === 'bindable_prop'`). The check `declarator.id.type !== 'Identifier'` triggers the throw.
Common situations: Components that destructure config objects as props, e.g. `export let { theme, size } = config`. Common in design-system and UI-kit components written for Svelte 4.
Related errors
- $$props is used together with named props in a way that cann
- migrating this component would require adding a `$${rune}` r
- Can't migrate code with ${illegal_specifiers.join(' and ')}.
- 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/b6ac5331176d3169.
Report an issue: GitHub.