{"record":{"id":"65c492540618dcef","repo":"hakimel/reveal.js","slug":"async-markdown-parsing-is-not-supported-here-becau","errorCode":null,"errorMessage":"Async markdown parsing is not supported here because Reveal markdown parsing is synchronous.","messagePattern":"Async markdown parsing is not supported here because Reveal markdown parsing is synchronous\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"react/src/utils/markdown.ts","lineNumber":113,"sourceCode":"\t\t\tconst text = token.tokens ? this.parser.parseInline(token.tokens) : token.text || '';\n\t\t\treturn `<li class=\"fragment\">${text}</li>`;\n\t\t};\n\t}\n\n\tconst markedInstance = new Marked();\n\tmarkedInstance.use({ renderer, ...markedOptions });\n\n\tif (smartypants) {\n\t\tmarkedInstance.use(markedSmartypants());\n\t}\n\n\treturn markedInstance;\n}\n\nfunction ensureParsedMarkdown(result: string | Promise<string>) {\n\tif (typeof result === 'string') return result;\n\n\tthrow new Error(\n\t\t'Async markdown parsing is not supported here because Reveal markdown parsing is synchronous.'\n\t);\n}\n\nfunction createSlideHtml(markdown: string, markedInstance: Marked, notesSeparator: string) {\n\tconst notesMatch = markdown.split(new RegExp(notesSeparator, 'mgi'));\n\tlet slideMarkdown = markdown;\n\tlet notesHtml = '';\n\n\tif (notesMatch.length === 2) {\n\t\tslideMarkdown = notesMatch[0];\n\t\tnotesHtml = `<aside class=\"notes\">${ensureParsedMarkdown(\n\t\t\tmarkedInstance.parse(notesMatch[1].trim())\n\t\t)}</aside>`;\n\t}\n\n\treturn `${ensureParsedMarkdown(markedInstance.parse(slideMarkdown))}${notesHtml}`;\n}","sourceCodeStart":95,"sourceCodeEnd":131,"githubUrl":"https://github.com/hakimel/reveal.js/blob/a3b940695648aa1c5b0680bc9a5b905cf43020e5/react/src/utils/markdown.ts#L95-L131","documentation":"ensureParsedMarkdown (react/src/utils/markdown.ts:110) guards the contract that Reveal markdown parsing stays synchronous. It is called on the result of markedInstance.parse(...) inside createSlideHtml (:125). When marked is configured in async mode (async:true, async walkTokens, or an async extension), parse returns a Promise<string>, which this guard rejects. Reveal's slide pipeline cannot await, so async results are treated as programmer error rather than deferred.","triggerScenarios":"Passing markedOptions.async = true (or any object whose async flag is truthy) into the Markdown component's marked config; registering a marked extension with an async walkTokens or async tokenizer/lexer; upgrading marked and inheriting a default that flips parse to async; supplying a custom renderer that returns a Promise.","commonSituations":"Developers adding marked plugins (e.g. async syntax highlighters, remote-data extensions) that turn parsing async; assuming marked.parse is always synchronous; copying marked options from a Node sample that used async:true for streaming.","solutions":["Remove async:true and any async walkTokens/tokenizer from the marked configuration passed to the Markdown component — parsing must stay synchronous.","If you need async data (e.g. fetched snippets or highlighted code), resolve it before passing the final string as the markdown/children, so parse only does synchronous work.","Pin/verify the marked version, since the sync-vs-async default has changed across major versions.","If a third-party marked extension forces async, replace it with a synchronous equivalent or preprocess its output upstream."],"exampleFix":"// before — forces async parsing\n<Markdown markedOptions={{ async: true, walkTokens: async (t) => { await fetchMeta(t); } }} />\n\n// after — keep parsing synchronous; resolve async data beforehand\nconst slides = await resolveAllSnippets(rawMarkdown);\nreturn <Markdown>{slides}</Markdown>;","handlingStrategy":"validation","validationCode":"function assertSyncMarkedOptions(markedOptions) {\n  if (markedOptions?.async === true) {\n    throw new Error('Reveal markdown requires synchronous marked; remove async:true.');\n  }\n  if (typeof markedOptions?.walkTokens?.constructor?.name === 'AsyncFunction') {\n    throw new Error('Reveal markdown requires a synchronous walkTokens.');\n  }\n  return markedOptions;\n}","typeGuard":"function isSyncParseResult(result) {\n  return typeof result === 'string';\n}","tryCatchPattern":null,"preventionTips":["Never set markedOptions.async when using the Markdown component.","Audit marked extensions for async walkTokens/tokenizers before registering them.","Resolve any remote/async content upstream and feed the final string into the component.","Pin the marked major version; re-test markdown parsing on upgrades."],"tags":["markdown","async","marked","react-wrapper","synchronous"],"backgroundTag":null,"analyzedSha":"a3b940695648aa1c5b0680bc9a5b905cf43020e5","analyzedAt":"2026-08-12T23:46:52.821Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}