{"record":{"id":"558b59c517867577","repo":"slidevjs/slidev","slug":"magic-move-block-must-contain-at-least-one-code-bl","errorCode":null,"errorMessage":"Magic Move block must contain at least one code block","messagePattern":"Magic Move block must contain at least one code block","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/slidev/node/syntax/codeblock/magic-move.ts","lineNumber":55,"sourceCode":"\n    const info = `${snippet.lang} ${snippet.meta}`.trim()\n    const content = snippet.content.endsWith('\\n') ? snippet.content : `${snippet.content}\\n`\n    return `\\`\\`\\`${info}\\n${content}\\`\\`\\``\n  }).join('\\n')\n}\n\nexport default defineCodeblockTransformer(async ({ info, fence, code, slide, options: { userRoot, data: { config, watchFiles }, utils: { shikiOptions, shiki } } }) => {\n  if (fence !== 4)\n    return\n  const match = info.match(RE_MAGIC_MOVE_INFO)\n  if (!match)\n    return\n  const [, title = '', options = '{}'] = match\n  const defaultLineNumbers = parseLineNumbersOption(options) ?? config.lineNumbers\n  const resolvedCode = slide ? resolveMagicMoveSnippetImports(code, userRoot, slide, watchFiles) : code\n  const matches = Array.from(resolvedCode.matchAll(RE_CODE_BLOCK))\n  if (!matches.length)\n    throw new Error('Magic Move block must contain at least one code block')\n\n  const ranges = matches.map(i => normalizeRangeStr(i[3]))\n  const steps = await Promise.all(matches.map(async (i) => {\n    const lang = i[1]\n    const lineNumbers = parseLineNumbersOption(i[4]) ?? defaultLineNumbers\n    const code = i[6].trimEnd()\n    const options = {\n      ...shikiOptions,\n      lang,\n    }\n    const { tokens, bg, fg, rootStyle, themeName } = await shiki.codeToTokens(code, options)\n    return {\n      ...toKeyedTokens(code, tokens, JSON.stringify([lang, 'themes' in options ? options.themes : options.theme]), lineNumbers),\n      bg,\n      fg,\n      rootStyle,\n      themeName,\n      lang,","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/slidevjs/slidev/blob/0d798ace5828966d9f77f62094d5f7a971ad98f7/packages/slidev/node/syntax/codeblock/magic-move.ts#L37-L73","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","solutions":["Add at least one triple-backtick code block inside the magic-move container as a step.","Ensure inner fences use exactly three backticks and the closing fence is at column 0, matching RE_CODE_BLOCK.","If using <<< snippet imports inside magic-move, verify they resolve to non-empty fenced code.","Provide multiple steps to actually see the animation; one step is the minimum but two-plus is the intent."],"exampleFix":"// before: magic-move with no inner code block\n````md magic-move\nSome prose only.\n````\n\n// after: at least one fenced step\n````md magic-move\n```js\nconst a = 1\n```\n```js\nconst a = 2\n```\n````","handlingStrategy":"validation","validationCode":"const RE_CODE_BLOCK = /^```[\\w'-]+[\\s\\S]*?^```$/gm\n\nfunction hasInnerCodeBlock(body: string): boolean {\n  return RE_CODE_BLOCK.test(body)\n}\n\n// before publishing a deck, scan magic-move blocks:\nif (!hasInnerCodeBlock(magicMoveBody)) {\n  throw new Error('magic-move block needs at least one fenced code step')\n}","typeGuard":"function isValidMagicMoveBody(body: string): boolean {\n  return /^```/m.test(body) && /\\n```\\s*$/m.test(body)\n}","tryCatchPattern":"try {\n  await renderSlide(md)\n} catch (e) {\n  if (e instanceof Error && e.message === 'Magic Move block must contain at least one code block') {\n    return { error: 'Add at least one ``` fenced code step inside the magic-move block.' }\n  }\n  throw e\n}","preventionTips":["Always include at least two ``` code steps inside a ````md magic-move block (one minimum, two for animation).","Use exactly three backticks for inner fences and four for the outer container.","Place inner closing fences at column 0 to match RE_CODE_BLOCK.","Verify <<< snippet imports inside magic-move resolve to non-empty fenced code."],"tags":["syntax","magic-move","codeblock","validation"],"backgroundTag":null,"analyzedSha":"0d798ace5828966d9f77f62094d5f7a971ad98f7","analyzedAt":"2026-08-12T17:10:56.221Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}