{"record":{"id":"e6ba38d9ebf9f7fc","repo":"sveltejs/svelte","slug":"props-is-used-together-with-named-props-in-a-way","errorCode":null,"errorMessage":"$$props is used together with named props in a way that cannot be automatically migrated.","messagePattern":"\\$\\$props is used together with named props in a way that cannot be automatically migrated\\.","errorType":"exception","errorClass":"MigrationError","httpStatus":null,"severity":"warning","filePath":"packages/svelte/src/compiler/migrate/index.js","lineNumber":636,"sourceCode":"\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\n\t\t\t\t\t// \t\t});\n\t\t\t\t\t// \t\tstate.props_insertion_point = /** @type {number} */(declarator.end);\n\t\t\t\t\t// \t} else {\n\t\t\t\t\t// \t\tdeclarations.push(b.declarator(path.node, value));\n\t\t\t\t\t// \t}\n\t\t\t\t\t// }\n\t\t\t\t}\n\n\t\t\t\tconst name = declarator.id.name;\n\t\t\t\tconst binding = /** @type {Binding} */ (state.scope.get(name));\n\n\t\t\t\tif (state.analysis.uses_props && (declarator.init || binding.updated)) {\n\t\t\t\t\tthrow new MigrationError(\n\t\t\t\t\t\t'$$props is used together with named props in a way that cannot be automatically migrated.'\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\tconst prop = state.props.find((prop) => prop.exported === (binding.prop_alias || name));\n\t\t\t\tif (prop) {\n\t\t\t\t\tnext();\n\t\t\t\t\t// $$Props type was used\n\t\t\t\t\tprop.init = declarator.init\n\t\t\t\t\t\t? state.str\n\t\t\t\t\t\t\t\t.snip(\n\t\t\t\t\t\t\t\t\t/** @type {number} */ (declarator.init.start),\n\t\t\t\t\t\t\t\t\t/** @type {number} */ (declarator.init.end)\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t.toString()\n\t\t\t\t\t\t: '';\n\t\t\t\t\tprop.bindable = binding.updated;\n\t\t\t\t\tprop.exported = binding.prop_alias || name;","sourceCodeStart":618,"sourceCodeEnd":654,"githubUrl":"https://github.com/sveltejs/svelte/blob/20b341f10048cf1016a2028ac7eee5595cfef6a5/packages/svelte/src/compiler/migrate/index.js#L618-L654","documentation":"Thrown when a component both consumes `$$props` (the legacy catch-all prop bag) and declares named props that have initializers or are mutated (`binding.updated`). The automigrator cannot decide how to merge a spread props object with explicit prop bindings, so it bails. The condition is `state.analysis.uses_props && (declarator.init || binding.updated)`.","triggerScenarios":"Running `migrate()` on a Svelte 4 component that combines `export let foo = ...` (or mutates a prop) with a read of `$$props` (e.g. forwarding unknown attributes: `<Child {...$$props} />`). The two patterns map to incompatible runes-mode translations.","commonSituations":"Attribute-forwarding components — a Svelte 4 idiom where `$$props` is spread onto a child while specific props are also declared and given defaults or reassigned. Wrapper/facade components around native elements frequently do this.","solutions":["Stop reading `$$props` and switch to explicit prop declarations before migrating.","Use `restProps` via `let { foo, ...rest } = $props()` after migration and spread `rest` instead of `$$props`.","Migrate the file by hand: split the named props into `$props()` and forward the remainder via a rest binding."],"exampleFix":"// before\n<script>\n  export let foo = 1;\n  $: foo++;\n</script>\n<Child {...$$props} />\n\n// after (manual)\n<script>\n  let { foo = $bindable(1), ...rest } = $props();\n  foo++;\n</script>\n<Child {...rest} />","handlingStrategy":"validation","validationCode":"// Detect the combined $$props + named/mutable prop pattern.\nfunction usesPropsBagAndMutatedProps(source) {\n  return /\\$\\$props/.test(source) && /export\\s+let\\s+\\w+\\s*=/.test(source);\n}\nif (usesPropsBagAndMutatedProps(componentSource)) {\n  // decide between rest-props forwarding and explicit prop declarations\n}","typeGuard":null,"tryCatchPattern":"const { code } = migrate({ filename, source });\nif (code.startsWith('<!-- @migration-task') && /\\$\\$props is used together with named props/i.test(code)) {\n  // hand-migrate: `let { namedProp, ...rest } = $props()` and spread `rest`\n}","preventionTips":["Pick one strategy for attribute forwarding — explicit props OR `$$props` spread — not both.","In Svelte 4 wrappers, prefer a rest-props pattern (`export let ...rest` via a helper) over `$$props`.","Pre-migrate components that mutate their own props to use local state instead."],"tags":["svelte5","migration","props","rest-props","codemod"],"backgroundTag":null,"analyzedSha":"20b341f10048cf1016a2028ac7eee5595cfef6a5","analyzedAt":"2026-08-12T23:37:30.399Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}