{"record":{"id":"d1eaa656e730e0c4","repo":"vuejs/vue","slug":"vue-compiler-sfc-script-and-script-setup-mu","errorCode":null,"errorMessage":"[@vue/compiler-sfc] <script> and <script setup> must have the same language type.","messagePattern":"\\[@vue/compiler-sfc\\] <script> and <script setup> must have the same language type\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/compiler-sfc/src/compileScript.ts","lineNumber":177,"sourceCode":"        )\n        content += `\\nexport default ${DEFAULT_VAR}`\n      }\n      return {\n        ...script,\n        content,\n        map,\n        bindings,\n        scriptAst: scriptAst.body\n      }\n    } catch (e: any) {\n      // silently fallback if parse fails since user may be using custom\n      // babel syntax\n      return script\n    }\n  }\n\n  if (script && scriptLang !== scriptSetupLang) {\n    throw new Error(\n      `[@vue/compiler-sfc] <script> and <script setup> must have the same ` +\n        `language type.`\n    )\n  }\n\n  if (scriptSetupLang && !isTS && scriptSetupLang !== 'jsx') {\n    // do not process non js/ts script blocks\n    return scriptSetup\n  }\n\n  // metadata that needs to be returned\n  const bindingMetadata: BindingMetadata = {}\n  const helperImports: Set<string> = new Set()\n  const userImports: Record<string, ImportBinding> = Object.create(null)\n  const userImportAlias: Record<string, string> = Object.create(null)\n  const scriptBindings: Record<string, BindingTypes> = Object.create(null)\n  const setupBindings: Record<string, BindingTypes> = Object.create(null)\n","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/vuejs/vue/blob/9e88707940088cb1f4cd7dd210c9168a50dc347c/packages/compiler-sfc/src/compileScript.ts#L159-L195","documentation":"Thrown when an SFC has both a normal <script> block and a <script setup> block but their lang attributes differ (e.g. <script lang=\"ts\"> with <script setup>). The compiler merges the two and cannot do so safely across language boundaries because babel parser plugins differ per language. Both blocks must share the same language type (js, ts, tsx, jsx) or be unspecified.","triggerScenarios":"An SFC declares <script lang=\"ts\"> and <script setup> (no lang, defaults to js), or vice versa. compileScript reads scriptLang and scriptSetupLang from the descriptor and compares them; any mismatch throws.","commonSituations":"Developer adds <script setup> to an existing TypeScript SFC but forgets to add lang=\"ts\" to the new block. Migration tooling that splits a single <script> into <script> + <script setup> may drop the lang attribute. Copy-paste between components with inconsistent lang settings.","solutions":["Make the lang attribute identical on both blocks: set both to lang=\"ts\", both to lang=\"tsx\", or remove lang from both.","If using <script setup> only for setup logic and <script> for side-effect imports, ensure both carry the same lang.","Remove the normal <script> block if all logic fits in <script setup>."],"exampleFix":"<!-- before -->\n<script lang=\"ts\">\nimport { foo } from './foo'\n</script>\n<script setup>\nconst bar = 1\n</script>\n\n<!-- after -->\n<script lang=\"ts\">\nimport { foo } from './foo'\n</script>\n<script setup lang=\"ts\">\nconst bar = 1\n</script>","handlingStrategy":"validation","validationCode":"function scriptLangsMatch(descriptor: SFCDescriptor): boolean {\n  const a = descriptor.script?.lang || ''\n  const b = descriptor.scriptSetup?.lang || ''\n  return a === b\n}\n\nif (descriptor.script && descriptor.scriptSetup && !scriptLangsMatch(descriptor)) {\n  throw new Error(`Lang mismatch: <script lang=\"${descriptor.script.lang}\"> vs <script setup lang=\"${descriptor.scriptSetup.lang}\">`)\n}","typeGuard":"function hasConsistentScriptLang(descriptor: SFCDescriptor): boolean {\n  if (!descriptor.script || !descriptor.scriptSetup) return true\n  return (descriptor.script.lang || '') === (descriptor.scriptSetup.lang || '')\n}","tryCatchPattern":"try {\n  compileScript(descriptor, opts)\n} catch (e) {\n  if (e.message.includes('must have the same language type')) {\n    // surface to linting / show the user which blocks mismatch\n    diagnosticReporter.report(descriptor.filename, e.message)\n  }\n  throw e\n}","preventionTips":["Add an ESLint rule (e.g. via vue-eslint-parser) that flags mismatched lang attributes on <script> and <script setup>.","When migrating a <script> to add <script setup>, copy the lang attribute first.","Codemod tools that split <script> should propagate lang to both resulting blocks."],"tags":["vue","compiler-sfc","script-setup","typescript","language-mismatch"],"analyzedSha":"9e88707940088cb1f4cd7dd210c9168a50dc347c","analyzedAt":"2026-08-11T22:22:01.295Z","schemaVersion":2},"datasetVersion":"2026-08-12T05:08:24.936Z"}