slidevjs/slidev · error · Error
Slide ${no} is out of sync with its source file. Try again.
Error message
Slide ${no} is out of sync with its source file. Try again. What it means
Thrown by removeSlide when md.slides.indexOf(slide.source) returns -1, i.e. the rendered slide's SourceSlideInfo object is not a member of its own markdown file's slides array. This is an internal consistency check indicating the in-memory deck is out of sync with its source.
Source
Thrown at packages/slidev/node/mcp/operations.ts:144
return { source, filepath: md.filepath, fileContent }
}
export interface RemoveSlideResult {
removed: SlideInfo
filepath: string
fileContent: string
}
/**
* Remove a slide from its source markdown file.
*/
export async function removeSlide(data: LoadedSlidevData, no: number): Promise<RemoveSlideResult> {
const slide = resolveSlide(data, no)
assertNotEntryHeadmatter(data, slide.source, 'remove')
const md = getMarkdown(data, slide.source)
const idx = md.slides.indexOf(slide.source)
if (idx < 0)
throw new Error(`Slide ${no} is out of sync with its source file. Try again.`)
md.slides.splice(idx, 1)
const fileContent = await parser.save(md)
return { removed: slide, filepath: md.filepath, fileContent }
}
export interface MoveSlideOptions {
/** Rendered slide number (1-based) of the slide to move */
from: number
/** Move the slide right before this rendered slide number */
before?: number
/** Move the slide right after this rendered slide number */
after?: number
}
export interface MoveSlideResult {
moved: SlideInfo
anchor: SlideInfo
filepath: stringView on GitHub (pinned to 0d798ace58)
Solutions
- Re-fetch data via ctx.getData() immediately before removeSlide and retry.
- Avoid concurrent edits to the same markdown file while an MCP operation is in flight.
- If the error persists, reload the dev server so parser state is rebuilt from disk.
Example fix
// before: cached data across an external edit const data = await ctx.getData() // external editor saves slides.md, shifting indices await removeSlide(data, 3) // throws: out of sync // after: fresh data per mutation const data = await ctx.getData() await removeSlide(data, 3)
Defensive patterns
Strategy: retry
Validate before calling
function slideInFile(md: { slides: SourceSlideInfo[] }, source: SourceSlideInfo): boolean {
return md.slides.indexOf(source) >= 0
}
// before removeSlide, with fresh data:
const data = await ctx.getData()
const slide = resolveSlide(data, no)
const md = data.markdownFiles[slide.source.filepath]
if (!md || !slideInFile(md, slide.source)) {
// refresh and abort if still stale
return
} Type guard
function slideSourceIsCurrent(
md: { slides: SourceSlideInfo[] },
source: SourceSlideInfo,
): source is SourceSlideInfo {
return md.slides.indexOf(source) >= 0
} Try / catch
try {
return await removeSlide(data, no)
} catch (e) {
if (e instanceof Error && /out of sync/.test(e.message)) {
data = await ctx.getData() // one refresh+retry
return await removeSlide(data, no)
}
throw e
} Prevention
- Call ctx.getData() per mutation; do not reuse snapshots.
- Serialize MCP writers per markdown file.
- Pause external editors while batch-editing via MCP.
- After HMR reloads, re-fetch data before the next op.
When it happens
Trigger: Calling removeSlide(data, no) after the underlying markdown file was edited externally (or by another tool) without refreshing data, so slide.source is a stale object reference no longer present in md.slides.
Common situations: Two concurrent MCP clients editing the same deck; an editor save + HMR reload interleaving with the tool call; reusing a getData() snapshot across a save.
Related errors
- Slide ${from} is out of sync with its source file. Try again
- Slide ${anchorNo} is out of sync with its source file. Try a
- Markdown file not loaded: ${source.filepath}
- Slide ${no} does not exist. The deck has ${data.slides.lengt
- Cannot ${action} the first slide of the entry file: its fron
AI-assisted analysis of slidevjs/slidev@0d798ace58 (2026-08-12).
Data as JSON: /api/errors/74ea9d6dacced3fc.
Report an issue: GitHub.