CherryHQ/cherry-studio · warning · Error
Path is not a file: ${filePath}
Error message
Path is not a file: ${filePath} What it means
fs.stat on the validated edit target succeeded but stats.isFile() returned false — the path resolves to a directory (or other non-file type) but the edit tool requires a regular file. The user-facing filePath appears in the message. This is a semantic mismatch, not a missing file (ENOENT is handled separately at edit.ts:51).
Source
Thrown at src/main/ai/mcp/servers/filesystem/tools/edit.ts:48
}
// Handler implementation
export async function handleEditTool(args: unknown, baseDir: string) {
const parsed = EditToolSchema.safeParse(args)
if (!parsed.success) {
throw new Error(`Invalid arguments for edit: ${parsed.error}`)
}
const { file_path: filePath, old_string: oldString, new_string: newString, replace_all: replaceAll } = parsed.data
// Validate path
const validPath = await validatePath(filePath, baseDir)
// Check if file exists
try {
const stats = await fs.stat(validPath)
if (!stats.isFile()) {
throw new Error(`Path is not a file: ${filePath}`)
}
} catch (error: any) {
if (error.code === 'ENOENT') {
// If old_string is empty, this is a create new file operation
if (oldString === '') {
// Create parent directory if needed
const parentDir = path.dirname(validPath)
await fs.mkdir(parentDir, { recursive: true })
// Write the new content
await fs.writeFile(validPath, newString, 'utf-8')
logger.info('File created', { path: validPath })
const relativePath = path.relative(baseDir, validPath)
return {
content: [
{View on GitHub (pinned to 726446b54c)
Solutions
- Confirm the path points to a regular file — use the ls or read tool first.
- If the intent is to edit multiple files, call edit once per file with a concrete file path.
- Strip any trailing slash from the path before sending, since directories are often written that way.
Example fix
// before
if (!stats.isFile()) {
throw new Error(`Path is not a file: ${filePath}`)
}
// after — say what it actually is
const kind = stats.isDirectory() ? 'directory' : stats.isSymbolicLink() ? 'symlink' : 'non-file'
throw new Error(`Path is a ${kind}, not a file: ${filePath}`) Defensive patterns
Strategy: validation
Validate before calling
// Confirm the target is a regular file before editing.
import { stat } from 'fs/promises'
async function assertIsFile(p: string): Promise<void> {
const s = await stat(p)
if (!s.isFile()) throw new Error(`Path is not a file: ${p}`)
} Prevention
- Call read or ls first to confirm the path is a file, not a directory.
- Strip trailing slashes from paths before sending.
- Edit one file per call; do not pass a directory path expecting bulk edits.
- Resolve symlinks before checking type if symlinks are present in the workspace.
When it happens
Trigger: The caller passed a directory path to the edit tool, expecting it to edit 'all files inside' or treating a directory like a file. Also fires for special files (device, socket) that are not regular files.
Common situations: A model confusing a directory path (e.g. '/src/components') with a file path ('/src/components/Button.tsx'); passing a path that points at a symlink to a directory.
Related errors
- Invalid arguments for edit: ${parsed.error}
- File not found: ${filePath}
- Path is not a directory: ${validPath}
- Unknown tool: ${name}
- Invalid arguments for delete: ${parsed.error}
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/9ba0a76f9811c806.
Report an issue: GitHub.