hakimel/reveal.js · error · Error
Async markdown parsing is not supported here because Reveal
Error message
Async markdown parsing is not supported here because Reveal markdown parsing is synchronous.
What it means
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.
Source
Thrown at react/src/utils/markdown.ts:113
const text = token.tokens ? this.parser.parseInline(token.tokens) : token.text || '';
return `<li class="fragment">${text}</li>`;
};
}
const markedInstance = new Marked();
markedInstance.use({ renderer, ...markedOptions });
if (smartypants) {
markedInstance.use(markedSmartypants());
}
return markedInstance;
}
function ensureParsedMarkdown(result: string | Promise<string>) {
if (typeof result === 'string') return result;
throw new Error(
'Async markdown parsing is not supported here because Reveal markdown parsing is synchronous.'
);
}
function createSlideHtml(markdown: string, markedInstance: Marked, notesSeparator: string) {
const notesMatch = markdown.split(new RegExp(notesSeparator, 'mgi'));
let slideMarkdown = markdown;
let notesHtml = '';
if (notesMatch.length === 2) {
slideMarkdown = notesMatch[0];
notesHtml = `<aside class="notes">${ensureParsedMarkdown(
markedInstance.parse(notesMatch[1].trim())
)}</aside>`;
}
return `${ensureParsedMarkdown(markedInstance.parse(slideMarkdown))}${notesHtml}`;
}View on GitHub (pinned to a3b9406956)
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.
Example fix
// before — forces async parsing
<Markdown markedOptions={{ async: true, walkTokens: async (t) => { await fetchMeta(t); } }} />
// after — keep parsing synchronous; resolve async data beforehand
const slides = await resolveAllSnippets(rawMarkdown);
return <Markdown>{slides}</Markdown>; Defensive patterns
Strategy: validation
Validate before calling
function assertSyncMarkedOptions(markedOptions) {
if (markedOptions?.async === true) {
throw new Error('Reveal markdown requires synchronous marked; remove async:true.');
}
if (typeof markedOptions?.walkTokens?.constructor?.name === 'AsyncFunction') {
throw new Error('Reveal markdown requires a synchronous walkTokens.');
}
return markedOptions;
} Type guard
function isSyncParseResult(result) {
return typeof result === 'string';
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of hakimel/reveal.js@a3b9406956 (2026-08-12).
Data as JSON: /api/errors/65c492540618dcef.
Report an issue: GitHub.