vuejs/core · error · Error
[@vue/compiler-sfc] <script> and <script setup> must have th
Error message
[@vue/compiler-sfc] <script> and <script setup> must have the same language type.
What it means
Thrown by compileScript in @vue/compiler-sfc when an SFC declares BOTH a normal <script> block and a <script setup> block but their lang attributes differ. Vue merges the two blocks into one module, so they must compile under the same language pipeline. The check at compileScript.ts:189 compares script.lang against scriptSetup.lang and aborts before any transformation runs.
Source
Thrown at packages/compiler-sfc/src/compileScript.ts:189
): SFCScriptBlock {
if (!options.id) {
warnOnce(
`compileScript now requires passing the \`id\` option.\n` +
`Upgrade your vite or vue-loader version for compatibility with ` +
`the latest experimental proposals.`,
)
}
const { script, scriptSetup, source, filename } = sfc
const hoistStatic = options.hoistStatic !== false && !script
const scopeId = options.id ? options.id.replace(/^data-v-/, '') : ''
const scriptLang = script && script.lang
const scriptSetupLang = scriptSetup && scriptSetup.lang
const isJSOrTS =
isJS(scriptLang, scriptSetupLang) || isTS(scriptLang, scriptSetupLang)
if (script && scriptSetup && scriptLang !== scriptSetupLang) {
throw new Error(
`[@vue/compiler-sfc] <script> and <script setup> must have the same ` +
`language type.`,
)
}
if (!scriptSetup) {
if (!script) {
throw new Error(`[@vue/compiler-sfc] SFC contains no <script> tags.`)
}
// normal <script> only
if (script.lang && !isJSOrTS) {
// do not process non js/ts script blocks
return script
}
const ctx = new ScriptCompileContext(sfc, options)
return processNormalScript(ctx, scopeId)View on GitHub (pinned to a2b40db9a8)
Solutions
- Make both <script> and <script setup> use the same lang attribute (usually both lang="ts").
- If the normal <script> only exists for side-effect imports or options that belong in setup, move that content into <script setup> and remove the duplicate block.
- If you genuinely need two languages, split the logic into a separate imported .ts/.js module instead of a second SFC script block.
Example fix
// before
<script lang="ts">
export default { inheritAttrs: false }
</script>
<script setup lang="tsx">
// ...
</script>
// after
<script lang="ts">
export default { inheritAttrs: false }
</script>
<script setup lang="ts">
// ...
</script> Defensive patterns
Strategy: validation
Validate before calling
// Before compileScript, verify both script blocks share a lang.
function canCompileScript(sfc: { script?: { lang?: string }; scriptSetup?: { lang?: string } }) {
if (sfc.script && sfc.scriptSetup) {
const a = sfc.script.lang || ''
const b = sfc.scriptSetup.lang || ''
if (a !== b) return false
}
return true
} Type guard
function scriptLangsMatch(sfc: { script?: { lang?: string }; scriptSetup?: { lang?: string } }): boolean {
if (!sfc.script || !sfc.scriptSetup) return true
return (sfc.script.lang || '') === (sfc.scriptSetup.lang || '')
} Prevention
- Pick one lang (usually 'ts') for all script blocks in an SFC.
- Lint .vue files with eslint-plugin-vue to catch mismatched script lang early.
- In SFC pipelines, short-circuit compileScript when langs differ and report a clear source-span error.
When it happens
Trigger: An .vue file containing e.g. <script lang="ts"> and <script setup lang="tsx">, or <script> (no lang, JS) next to <script setup lang="ts">. Calling compileScript(sfc, options) on such an SFC reproduces it.
Common situations: Mixing a TypeScript <script setup> with a plain JS <script> for non-setup exports; copy-pasting a script block from another SFC with a different lang; tooling that injects a <script> block with a default lang.
Related errors
- [@vue/compiler-sfc] SFC contains no <script> tags.
- [@vue/compiler-sfc] `modules` option is not supported in the
- [@vue/compiler-sfc] `modules` option can only be used with c
- [@vue/compiler-sfc] Style preprocessing in the browser build
- [@vue/compiler-sfc] Template preprocessing in the browser bu
AI-assisted analysis of vuejs/core@a2b40db9a8 (2026-08-12).
Data as JSON: /api/errors/f9871382e95e5a49.
Report an issue: GitHub.