modelcontextprotocol/servers · error · Error
Parent directory does not exist: ${parentDir}
Error message
Parent directory does not exist: ${parentDir} What it means
Thrown by `validatePath` when the target file does not exist (ENOENT) AND its parent directory also does not exist (realpath of the parent throws). This distinguishes a legitimate new-file creation (parent exists) from an impossible one (parent missing), preventing creation cascades into nonexistent locations.
Source
Thrown at src/filesystem/lib.ts:135
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') {
const parentDir = path.dirname(absolute);
try {
const realParentPath = await fs.realpath(parentDir);
const normalizedParent = normalizePath(realParentPath);
if (!isPathWithinAllowedDirectories(normalizedParent, allowedDirectories)) {
throw new Error(`Access denied - parent directory outside allowed directories: ${realParentPath} not in ${allowedDirectories.join(', ')}`);
}
return absolute;
} catch {
throw new Error(`Parent directory does not exist: ${parentDir}`);
}
}
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(),
isFile: stats.isFile(),
permissions: stats.mode.toString(8).slice(-3),View on GitHub (pinned to 76d64c822f)
Solutions
- Create the parent directory first with `create_directory`, then write the file.
- Verify the full parent path exists before issuing the write.
- Check for typos in intermediate directory names.
Example fix
// before
write_file({ path: '/home/me/projects/new/sub/x.txt', content: 'hi' })
// after
create_directory({ path: '/home/me/projects/new/sub' })
write_file({ path: '/home/me/projects/new/sub/x.txt', content: 'hi' }) Defensive patterns
Strategy: validation
Validate before calling
import fs from 'node:fs/promises';
async function parentExists(p: string): Promise<boolean> {
try { await fs.access(path.dirname(p)); return true; } catch { return false; }
}
if (!await parentExists(args.path)) {
await callTool('create_directory', { path: path.dirname(args.path) });
} Try / catch
try {
await writeFile({ path, content });
} catch (e) {
if (e instanceof Error && e.message.startsWith('Parent directory does not exist')) {
await createDirectory({ path: dirname(path) });
await writeFile({ path, content });
}
} Prevention
- Create parent directories with create_directory before writing files.
- Verify the full parent path exists before issuing writes.
- Check intermediate path segments for typos.
When it happens
Trigger: Calling a write/create tool with a path whose parent directory does not exist on disk — e.g. `write_file({ path: '/home/me/projects/nested/deep/x.txt' })` when `nested/deep` was never created.
Common situations: Forgetting to `create_directory` first, typos in intermediate path segments, or assuming a directory exists when it doesn't. The catch-all around the parent realpath turns any failure (including ENOENT of the parent) into this message.
Related errors
- Cannot specify both head and tail parameters simultaneously
- Access denied - path outside allowed directories: ${absolute
- Access denied - parent directory outside allowed directories
- Invalid resourceType: ${args?.resourceType}. Must be ${RESOU
- Invalid resourceId: ${args?.resourceId}. Must be a finite po
AI-assisted analysis of modelcontextprotocol/servers@76d64c822f (2026-08-12).
Data as JSON: /api/errors/8054b5f7dfebeda7.
Report an issue: GitHub.