CherryHQ/cherry-studio · error · Error
File not found in workspace: ${userPath}
Error message
File not found in workspace: ${userPath} What it means
Thrown by resolveWorkspaceFile() when realpath(requested) — the resolved target path — fails with ENOENT or ENOTDIR. This means the specific file the agent or user requested does not exist (or a path component is not a directory) within the workspace. The realpath call also resolves symlinks, so a dangling symlink to a non-existent target triggers this as well.
Source
Thrown at src/main/ai/channels/security/WorkspaceFileGuard.ts:43
let realRoot: string
try {
realRoot = await realpath(workspaceRoot)
} catch (error) {
// The root is a caller invariant, but if the session workspace is gone a bare ENOENT
// naming the root reads like "your file_path is wrong" — wrap it so the agent doesn't
// waste retries on other paths.
if (isErrnoException(error) && (error.code === 'ENOENT' || error.code === 'ENOTDIR')) {
throw new Error(`Session workspace is unavailable: ${workspaceRoot}`)
}
throw error
}
let realTarget: string
try {
realTarget = await realpath(requested)
} catch (error) {
if (isErrnoException(error) && (error.code === 'ENOENT' || error.code === 'ENOTDIR')) {
throw new Error(`File not found in workspace: ${userPath}`)
}
throw error
}
if (realTarget !== realRoot && !realTarget.startsWith(realRoot + path.sep)) {
throw new Error(`Path is outside the workspace: ${userPath}`)
}
return readCanonicalLocalFile(requested, realTarget, userPath)
}
View on GitHub (pinned to 726446b54c)
Solutions
- Re-list the workspace directory to confirm the file still exists before retrying the read.
- Check for typos or path-component case sensitivity (especially on case-sensitive filesystems).
- If the file was created by a prior agent step, verify that step completed successfully before this read.
Defensive patterns
Strategy: try-catch
Validate before calling
import { exists } from '@main/utils/file'
const resolvedPath = path.resolve(workspaceRoot, userPath)
if (!(await exists(resolvedPath))) {
// File doesn't exist — re-list the workspace to help the agent self-correct
logger.warn('Requested file not found in workspace', { userPath, resolvedPath })
return null
} Try / catch
try {
return await resolveWorkspaceFile(workspaceRoot, userPath)
} catch (error) {
if (error instanceof Error && error.message.startsWith('File not found in workspace:')) {
// Return null or re-list the workspace directory so the agent can pick a valid file
return null
}
throw error
} Prevention
- Re-list the workspace directory before reading files if there is any chance of concurrent modification.
- Cache workspace file listings with a short TTL to catch stale paths.
- When an agent selects a file path, validate it against the current listing before attempting a read.
When it happens
Trigger: Called from agent document/autonomy tools when the agent supplies a userPath that doesn't resolve to an existing file. Triggers when: the file was never created, was deleted between listing and read, a path component is a file instead of a directory (ENOTDIR), or a symlink points to a target that no longer exists.
Common situations: An agent hallucinated a file path from the workspace listing; the file was deleted by another process or agent step between the directory listing and the read attempt; the agent used a path from a prior session that no longer exists; a build step cleaned output directories that the agent expected to read.
Related errors
- Session workspace is unavailable: ${workspaceRoot}
- File not found: ${displayPath}
- File not found: ${userPath}
- Path is outside the workspace: ${userPath}
- Not a regular file: ${displayPath}
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/8d7c74bff5a96d44.
Report an issue: GitHub.