modelcontextprotocol/servers · error · Error
Parent directory does not exist: ${path.dirname(absolute)}
Error message
Parent directory does not exist: ${path.dirname(absolute)} What it means
When the requested path does not exist (realpath throws ENOENT), validatePath falls back to resolveUnicodeEquivalentPath to support mkdir -p style creation. If that fallback also fails with ENOENT, the nearest existing ancestor could not be resolved — meaning the parent directory chain is missing — so this error is thrown instead of silently creating directories in the wrong place.
Source
Thrown at src/filesystem/lib.ts:177
// Security: Handle symlinks by checking their real path to prevent symlink attacks
// This prevents attackers from creating symlinks that point outside allowed directories
try {
const realPath = await fs.realpath(absolute);
const normalizedReal = normalizePath(realPath);
if (!isPathWithinAllowedDirectories(normalizedReal, allowedDirectories)) {
throw new Error(`Access denied - symlink target outside allowed directories: ${realPath} not in ${allowedDirectories.join(', ')}`);
}
return realPath;
} catch (error) {
// Security: For new files that don't exist yet, verify parent directory
// This ensures we can't create files in unauthorized locations
if ((error as NodeJS.ErrnoException).code === 'ENOENT') {
try {
return await resolveUnicodeEquivalentPath(absolute);
} catch (resolutionError) {
if ((resolutionError as NodeJS.ErrnoException).code === 'ENOENT') {
throw new Error(`Parent directory does not exist: ${path.dirname(absolute)}`);
}
throw resolutionError;
}
}
throw error;
}
}
// File Operations
export async function getFileStats(filePath: string): Promise<FileInfo> {
const stats = await fs.stat(filePath);
return {
size: stats.size,
created: stats.birthtime,
modified: stats.mtime,
accessed: stats.atime,
isDirectory: stats.isDirectory(),View on GitHub (pinned to 579c3903f3)
Solutions
- Create the parent directory chain first (create_directory on the parent, then the target)
- Fix the typo/incorrect parent path in the request
- Verify each ancestor exists with list_directory or get_file_info before creating children
Example fix
// before: parents missing
await create_directory('/allowed/projects/app/src'); // ENOENT at 'app'
// after: create incrementally
await create_directory('/allowed/projects/app');
await create_directory('/allowed/projects/app/src'); Defensive patterns
Strategy: try-catch
Validate before calling
const parent = path.dirname(p);
try { await fs.access(parent); } catch {
throw new Error(`Create parent ${parent} before ${p}`);
} Try / catch
try {
await create_directory(p);
} catch (err) {
if (err.message.startsWith('Parent directory does not exist')) {
await create_directory(err.message.split(': ')[1]); // create parent, then retry
await create_directory(p);
} else throw err;
} Prevention
- Ensure every ancestor directory exists before creating children (mkdir -p semantics manually)
- Validate parent paths with get_file_info/list_directory first
- Check for typos in directory names
- Re-verify directories still exist after external deletions or rebases
When it happens
Trigger: create_directory or write-style calls targeting '/allowed/a/b/newdir' where the parent '/allowed/a/b' (or an earlier ancestor) does not exist, or where a symlinked ancestor chain is broken.
Common situations: Typos in the parent directory name; assuming the tool creates intermediate directories; a directory deleted between planning and execution; Unicode-normalized parents that fail to match (leading to nested ENOENT).
Related errors
- Parent directory does not exist: ${parentDir}
- Ambiguous Unicode path component: ${requestedPart}
- Could not find exact match for edit:\n${edit.oldText}
- Access denied - symlink target outside allowed directories:
- Access denied - Windows-style path received on a POSIX host:
AI-assisted analysis of modelcontextprotocol/servers@579c3903f3 (2026-09-01).
Data as JSON: /api/errors/68e85a54d059db50.
Report an issue: GitHub.