{"record":{"id":"b6ac5331176d3169","repo":"sveltejs/svelte","slug":"encountered-an-export-declaration-pattern-that-is","errorCode":null,"errorMessage":"Encountered an export declaration pattern that is not supported for automigration.","messagePattern":"Encountered an export declaration pattern that is not supported for automigration\\.","errorType":"exception","errorClass":"MigrationError","httpStatus":null,"severity":"warning","filePath":"packages/svelte/src/compiler/migrate/index.js","lineNumber":605,"sourceCode":"\t\t\t} catch (e) {\n\t\t\t\t// no bindings, so we can skip this\n\t\t\t\tnext();\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst has_state = bindings.some((binding) => binding.kind === 'state');\n\t\t\tconst has_props = bindings.some((binding) => binding.kind === 'bindable_prop');\n\n\t\t\tif (!has_state && !has_props) {\n\t\t\t\tnext();\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (has_props) {\n\t\t\t\tnr_of_props++;\n\n\t\t\t\tif (declarator.id.type !== 'Identifier') {\n\t\t\t\t\t// TODO invest time in this?\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t'Encountered an export declaration pattern that is not supported for automigration.'\n\t\t\t\t\t);\n\t\t\t\t\t// Turn export let into props. It's really really weird because export let { x: foo, z: [bar]} = ..\n\t\t\t\t\t// means that foo and bar are the props (i.e. the leaves are the prop names), not x and z.\n\t\t\t\t\t// const tmp = b.id(state.scope.generate('tmp'));\n\t\t\t\t\t// const paths = extract_paths(declarator.id, tmp);\n\t\t\t\t\t// state.props_pre.push(\n\t\t\t\t\t// \tb.declaration('const', tmp, visit(declarator.init!) as Expression)\n\t\t\t\t\t// );\n\t\t\t\t\t// for (const path of paths) {\n\t\t\t\t\t// \tconst name = (path.node as Identifier).name;\n\t\t\t\t\t// \tconst binding = state.scope.get(name)!;\n\t\t\t\t\t// \tconst value = path.expression;\n\t\t\t\t\t// \tif (binding.kind === 'bindable_prop' || binding.kind === 'rest_prop') {\n\t\t\t\t\t// \t\tstate.props.push({\n\t\t\t\t\t// \t\t\tlocal: name,\n\t\t\t\t\t// \t\t\texported: binding.prop_alias ? binding.prop_alias : name,\n\t\t\t\t\t// \t\t\tinit: value","sourceCodeStart":587,"sourceCodeEnd":623,"githubUrl":"https://github.com/sveltejs/svelte/blob/20b341f10048cf1016a2028ac7eee5595cfef6a5/packages/svelte/src/compiler/migrate/index.js#L587-L623","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before\n<script>\n  export let { theme, size } = config;\n</script>\n\n// after (manual migration)\n<script>\n  let { theme = $bindable(), size = $bindable() } = $props();\n</script>","handlingStrategy":"validation","validationCode":"// Detect destructuring export-let patterns before invoking migrate.\nfunction hasDestructuredExport(source) {\n  return /export\\s+let\\s*[\\[\\{]/.test(source);\n}\nif (hasDestructuredExport(componentSource)) {\n  // refactor to plain `export let x; export let y;` before migrating\n}","typeGuard":null,"tryCatchPattern":"const { code } = migrate({ filename, source });\nif (code.startsWith('<!-- @migration-task') && /export declaration pattern/i.test(code)) {\n  // hand-migrate the destructured export let to $props() with $bindable()\n}","preventionTips":["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."],"tags":["svelte5","migration","destructuring","props","codemod"],"backgroundTag":null,"analyzedSha":"20b341f10048cf1016a2028ac7eee5595cfef6a5","analyzedAt":"2026-08-12T23:37:30.399Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}