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

  1. Re-list the workspace directory to confirm the file still exists before retrying the read.
  2. Check for typos or path-component case sensitivity (especially on case-sensitive filesystems).
  3. 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

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


AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12). Data as JSON: /api/errors/8d7c74bff5a96d44. Report an issue: GitHub.