slidevjs/slidev · error · Error
Code snippet path escapes the project root: ${src}
Error message
Code snippet path escapes the project root: ${src} What it means
Thrown by resolveSnippetImport when the resolved absolute path of a <<< snippet import is not inside any of allowedRoots (userRoot + workspace root + extra roots). isPathInsideRoots rejects any path containing '..' traversal that escapes the root set. This is a security guard preventing deck files from reading arbitrary files outside the project.
Source
Thrown at packages/slidev/node/syntax/snippet.ts:128
export function resolveSnippetImport(lineText: string, userRoot: string, slide: SlideInfo, allowedRoots: string[] = [userRoot]) {
const match = lineText.trimStart().match(RE_SNIPPET_IMPORT)
if (!match)
return null
let [, filepath = '', regionName = '', lang = '', meta = ''] = match
const dir = path.dirname(slide.source.filepath)
const src = slash(
filepath.startsWith('@/')
? path.resolve(userRoot, filepath.slice(2))
: path.resolve(dir, filepath),
)
lang = lang.trim() || path.extname(filepath).slice(1)
meta = meta.trim()
if (!isPathInsideRoots(src, allowedRoots)) {
throw new Error(`Code snippet path escapes the project root: ${src}`)
}
const isAFile = fs.existsSync(src) && fs.statSync(src).isFile()
if (!isAFile) {
throw new Error(`Code snippet path not found: ${src}`)
}
let content = fs.readFileSync(src, 'utf8')
if (regionName) {
const lines = content.split(RE_NEWLINE)
const region = findRegion(lines, regionName.slice(1))
if (region) {
content = dedent(
lines
.slice(region.start, region.end)
.filter(l => !(region.re.start.test(l) || region.re.end.test(l)))
.join('\n'),View on GitHub (pinned to 0d798ace58)
Solutions
- Move the target file inside the project root (or a configured root) and reference it relatively.
- If you legitimately need a parent directory, add it to the Slidev roots config so isPathInsideRoots accepts it.
- Use the @/ alias to point at files under userRoot instead of ../ paths.
- Check that userRoot/workspace root are correct (entry file location drives userRoot).
Example fix
// before: escapes the project root <<< ../shared/snippet.ts // after: keep sources inside the project <<< @/shared/snippet.ts // (place the file under <userRoot>/shared/snippet.ts)
Defensive patterns
Strategy: validation
Validate before calling
import { isPathInsideRoots } from '@slidev/cli/node/utils'
import path from 'pathe'
import { slash } from '@antfu/utils'
function snippetInsideRoots(filepath: string, dir: string, userRoot: string, roots: string[]): boolean {
const src = slash(
filepath.startsWith('@/') ? path.resolve(userRoot, filepath.slice(2)) : path.resolve(dir, filepath),
)
return isPathInsideRoots(src, roots)
}
// before rendering, validate <<< lines:
if (!snippetInsideRoots(filepath, slideDir, userRoot, allowedRoots)) {
throw new Error(`Snippet escapes roots: ${filepath}`)
} Type guard
function snippetPathSafe(filepath: string, dir: string, userRoot: string, roots: string[]): boolean {
const src = slash(
filepath.startsWith('@/') ? path.resolve(userRoot, filepath.slice(2)) : path.resolve(dir, filepath),
)
return isPathInsideRoots(src, roots)
} Try / catch
try {
return resolveSnippetImport(line, userRoot, slide, allowedRoots)
} catch (e) {
if (e instanceof Error && e.message.startsWith('Code snippet path escapes the project root')) {
// drop the import or relocate the file inside the project
return null
}
throw e
} Prevention
- Keep snippet target files inside the project root or a configured Slidev root.
- Use the @/ alias for sources under userRoot instead of ../ paths.
- Add legitimate parent dirs to the roots config when shared code lives above the project.
- Reject user-supplied <<< paths in CI builds to prevent traversal.
When it happens
Trigger: Writing <<< ../secrets.env or <<< /etc/passwd in a slide, or any snippet path that, after path.resolve, lands outside every allowed root. Triggered at parse time when markdown-it renders the snippet block.
Common situations: Snippets referencing shared code in a parent directory of the project root; absolute paths to system files; symlinks that resolve outside the roots; misconfigured userRoot (e.g. entry resolved to the wrong directory).
Related errors
AI-assisted analysis of slidevjs/slidev@0d798ace58 (2026-08-12).
Data as JSON: /api/errors/0617793798a640b3.
Report an issue: GitHub.