slidevjs/slidev · error · Error

Magic Move block must contain at least one code block

Error message

Magic Move block must contain at least one code block

What it means

Thrown by the magic-move codeblock transformer when a quad-fence (````) block whose info line matches the magic-move pattern contains zero inner triple-fence code blocks (RE_CODE_BLOCK finds no matches). Magic Move animates between successive code steps, so at least one step is mandatory.

Source

Thrown at packages/slidev/node/syntax/codeblock/magic-move.ts:55

    const info = `${snippet.lang} ${snippet.meta}`.trim()
    const content = snippet.content.endsWith('\n') ? snippet.content : `${snippet.content}\n`
    return `\`\`\`${info}\n${content}\`\`\``
  }).join('\n')
}

export default defineCodeblockTransformer(async ({ info, fence, code, slide, options: { userRoot, data: { config, watchFiles }, utils: { shikiOptions, shiki } } }) => {
  if (fence !== 4)
    return
  const match = info.match(RE_MAGIC_MOVE_INFO)
  if (!match)
    return
  const [, title = '', options = '{}'] = match
  const defaultLineNumbers = parseLineNumbersOption(options) ?? config.lineNumbers
  const resolvedCode = slide ? resolveMagicMoveSnippetImports(code, userRoot, slide, watchFiles) : code
  const matches = Array.from(resolvedCode.matchAll(RE_CODE_BLOCK))
  if (!matches.length)
    throw new Error('Magic Move block must contain at least one code block')

  const ranges = matches.map(i => normalizeRangeStr(i[3]))
  const steps = await Promise.all(matches.map(async (i) => {
    const lang = i[1]
    const lineNumbers = parseLineNumbersOption(i[4]) ?? defaultLineNumbers
    const code = i[6].trimEnd()
    const options = {
      ...shikiOptions,
      lang,
    }
    const { tokens, bg, fg, rootStyle, themeName } = await shiki.codeToTokens(code, options)
    return {
      ...toKeyedTokens(code, tokens, JSON.stringify([lang, 'themes' in options ? options.themes : options.theme]), lineNumbers),
      bg,
      fg,
      rootStyle,
      themeName,
      lang,

View on GitHub (pinned to 0d798ace58)

Solutions

  1. Add at least one triple-backtick code block inside the magic-move container as a step.
  2. Ensure inner fences use exactly three backticks and the closing fence is at column 0, matching RE_CODE_BLOCK.
  3. If using <<< snippet imports inside magic-move, verify they resolve to non-empty fenced code.
  4. Provide multiple steps to actually see the animation; one step is the minimum but two-plus is the intent.

Example fix

// before: magic-move with no inner code block
````md magic-move
Some prose only.
````

// after: at least one fenced step
````md magic-move
```js
const a = 1
```
```js
const a = 2
```
````
Defensive patterns

Strategy: validation

Validate before calling

const RE_CODE_BLOCK = /^```[\w'-]+[\s\S]*?^```$/gm

function hasInnerCodeBlock(body: string): boolean {
  return RE_CODE_BLOCK.test(body)
}

// before publishing a deck, scan magic-move blocks:
if (!hasInnerCodeBlock(magicMoveBody)) {
  throw new Error('magic-move block needs at least one fenced code step')
}

Type guard

function isValidMagicMoveBody(body: string): boolean {
  return /^```/m.test(body) && /\n```\s*$/m.test(body)
}

Try / catch

try {
  await renderSlide(md)
} catch (e) {
  if (e instanceof Error && e.message === 'Magic Move block must contain at least one code block') {
    return { error: 'Add at least one ``` fenced code step inside the magic-move block.' }
  }
  throw e
}

Prevention

When it happens

Trigger: Writing a ````md magic-move ... ```` block whose body has no nested fenced code block - e.g. only prose, an empty body, or inner fences that don't match the strict RE_CODE_BLOCK pattern (wrong fence length, leading spaces).

Common situations: Forgetting to add the inner code step(s); using three backticks inside a four-backtick container without matching the regex; snippet imports that resolve to empty content; mismatched fence counts so the inner block isn't captured.

Related errors


AI-assisted analysis of slidevjs/slidev@0d798ace58 (2026-08-12). Data as JSON: /api/errors/558b59c517867577. Report an issue: GitHub.