slidevjs/slidev · critical · Error
[Slidev] Internal error: <script setup> block not found in s
Error message
[Slidev] Internal error: <script setup> block not found in slide ${index + 1}. What it means
This is an internal error thrown by Slidev's `slidev:layout-wrapper` Vite plugin when transforming a compiled markdown slide. After resolving the layout, the plugin regex-matches `/^<script setup.*>/m` (RE_SCRIPT_SETUP_TAG) against the slide's transformed code; every slide is expected to already contain a `<script setup>` block injected by an upstream pipeline stage. The throw fires only when that contract is broken — the slide reached the layout wrapper without a script-setup block, so the plugin cannot safely splice in the layout import and context setup it appends.
Source
Thrown at packages/slidev/node/vite/layoutWrapper.ts:40
if (!match)
return
const [, no, type] = match
if (type !== 'md')
return
const index = +no - 1
const layouts = await utils.getLayouts()
const rawLayoutName = data.slides[index]?.frontmatter?.layout ?? data.slides[0]?.frontmatter?.defaults?.layout
let layoutName = rawLayoutName || (index === 0 ? 'cover' : 'default')
if (!layouts[layoutName]) {
console.error(red(`\nUnknown layout "${bold(layoutName)}".${yellow(' Available layouts are:')}`)
+ Object.keys(layouts).map((i, idx) => (idx % 3 === 0 ? '\n ' : '') + gray(i.padEnd(15, ' '))).join(' '))
console.error()
layoutName = 'default'
}
const setupTag = code.match(RE_SCRIPT_SETUP_TAG)
if (!setupTag)
throw new Error(`[Slidev] Internal error: <script setup> block not found in slide ${index + 1}.`)
const templatePart = code.slice(0, setupTag.index!)
const scriptPart = code.slice(setupTag.index!)
const bodyStart = templatePart.indexOf('<template>') + 10
const bodyEnd = templatePart.lastIndexOf('</template>')
let body = code.slice(bodyStart, bodyEnd).trim()
if (body.startsWith('<div>') && body.endsWith('</div>'))
body = body.slice(5, -6)
return [
templatePart.slice(0, bodyStart),
`<InjectedLayout v-bind="_frontmatterToProps($frontmatter,${index})">\n${body}\n</InjectedLayout>`,
templatePart.slice(bodyEnd),
scriptPart.slice(0, setupTag[0].length),
`import InjectedLayout from "${toAtFS(layouts[layoutName])}"`,
templateImportContextUtils,
templateInitContext,View on GitHub (pinned to 0d798ace58)
Solutions
- This is an internal invariant — file a Slidev bug report with the slide content and the offending slide number from the message.
- Verify all @slidev/* packages resolve to the same version (run the version check / dedupe node_modules); a mixed-version install is the most common root cause.
- Audit any custom Vite plugins you added via `vitePlugins` or Slidev options for a `transform` hook that handles `*.md` ids and may strip or replace the `<script setup>` block before the layout-wrapper plugin runs.
- Disable third-party Vite/Vue plugins one at a time to isolate which transform removes the script-setup tag.
- Clear Vite's cache (`node_modules/.vite`) and restart the dev server to rule out a stale transform cache.
Example fix
// before: a custom plugin transforming md and dropping the script tag
transform(code, id) {
if (id.endsWith('.md')) return rewriteHtmlOnly(code) // drops <script setup>
}
// after: bail out for slide source ids so Slidev's pipeline owns them
import { regexSlideSourceId } from '@slidev/node/vite/common'
transform(code, id) {
if (regexSlideSourceId.test(id)) return // let Slidev handle slide modules
if (id.endsWith('.md')) return rewriteHtmlOnly(code)
} Defensive patterns
Strategy: validation
Validate before calling
// If you author custom Vite plugins, never strip the script-setup tag from
// slide source ids. Bail out for ids Slidev owns:
import { regexSlideSourceId } from '@slidev/node/vite/common'
function ownsSlide(id: string): boolean {
return regexSlideSourceId.test(id)
}
// in your transform: if (ownsSlide(id)) return undefined Type guard
// Guard the invariant the plugin relies on, for tests/diagnostics:
const RE_SCRIPT_SETUP_TAG = /^<script setup.*>/m
function hasScriptSetup(code: string): boolean {
return RE_SCRIPT_SETUP_TAG.test(code)
} Prevention
- Keep all @slidev/* packages on a single locked version (use the same release tag / lockfile dedupe).
- Do not write Vite transform plugins that rewrite `*.md` slide modules; let Slidev's pipeline own them.
- After upgrading Slidev, clear `node_modules/.vite` to prevent stale cached transforms.
- If you fork Slidev's markdown-to-SFC compiler, assert every emitted slide contains a `<script setup>` tag in your tests.
When it happens
Trigger: Fires inside the plugin's `transform.handler` for any module id matching `regexSlideSourceId` with type `md`. Concretely: `code.match(RE_SCRIPT_SETUP_TAG)` returns null. This happens when an earlier transform in the pipeline that is supposed to prepend the `<script setup>` block did not run, ran out of order, or was overridden by a custom user Vite plugin that rewrites/strips the slide module output before the layout wrapper sees it.
Common situations: Mismatched @slidev package versions (e.g. @slidev/client or @slidev/parser newer/older than @slidev/parser that emits the script setup), a custom Vite plugin in `vitePlugins`/`unocss` config that transforms `*.md` ids and clobbers the `<script setup>` tag, or a fork/patch of Slidev whose markdown-to-SFC compiler no longer emits the tag. The error names the offending slide by 1-based index (`index + 1`).
Related errors
- [slidev] The length of stepRanges does not match the length
- [Slidev] VDrag Element ${id} is missing markdown source
- [Slidev] VDrag Element ${id} is not found in the markdown so
- Package "${pkg}" not found in "${importer}"
- [slidev] Failed to load "${PWA_PACKAGE}", which is required
AI-assisted analysis of slidevjs/slidev@0d798ace58 (2026-08-12).
Data as JSON: /api/errors/4a5d319bd46d3372.
Report an issue: GitHub.