{"record":{"id":"cca76dbf5fef5b03","repo":"CherryHQ/cherry-studio","slug":"agent-data-directory-must-be-a-real-directory-a","errorCode":null,"errorMessage":"Agent data directory must be a real directory: ${agentDataPath}","messagePattern":"Agent data directory must be a real directory: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"src/main/ai/agents/agentDataDirectory.ts","lineNumber":167,"sourceCode":"  }\n\n  await mkdir(asAbsolutePath(agentDataPath))\n  try {\n    await ensureAgentDataDirectory(agentsDataRoot, agentId)\n    return agentDataPath\n  } catch (error) {\n    await removeAgentDataDirectory(agentsDataRoot, agentId).catch(() => undefined)\n    throw error\n  }\n}\n\nexport async function assertAgentDataDirectory(agentsDataRoot: string, agentId: string): Promise<string> {\n  const agentDataPath = agentDataDirectoryPath(agentsDataRoot, agentId)\n  await assertAgentStoragePath(agentsDataRoot, agentDataPath)\n\n  const rootStat = await lstatIfExists(agentDataPath)\n  if (!rootStat?.isDirectory || rootStat.isSymbolicLink) {\n    throw new Error(`Agent data directory must be a real directory: ${agentDataPath}`)\n  }\n\n  const memoryPath = path.join(agentDataPath, 'memory')\n  const memoryStat = await lstatIfExists(memoryPath)\n  if (!memoryStat?.isDirectory || memoryStat.isSymbolicLink) {\n    throw new Error(`Agent memory directory must be a real directory: ${memoryPath}`)\n  }\n\n  for (const filename of AGENT_DATA_FILES) {\n    const filePath = path.join(agentDataPath, filename)\n    const fileStat = await lstatIfExists(filePath)\n    if (fileStat && (!fileStat.isFile || fileStat.isSymbolicLink)) {\n      throw new Error(`Agent data file must be a real file: ${filePath}`)\n    }\n  }\n  return agentDataPath\n}\n","sourceCodeStart":149,"sourceCodeEnd":185,"githubUrl":"https://github.com/CherryHQ/cherry-studio/blob/726446b54cd69ffe51a276638672f6d95ca0768c/src/main/ai/agents/agentDataDirectory.ts#L149-L185","documentation":"Thrown by assertAgentDataDirectory while validating an agent's data store: the root agent data path exists but lstat reports it is not a directory, or it is a symbolic link. assertAgentDataDirectory is the integrity gate called by ensureAgentDataDirectory after creation, so a non-directory root means the data store is corrupt or has been tampered with.","triggerScenarios":"Any code path that runs assertAgentDataDirectory (directly or via ensureAgentDataDirectory/createAgentDataDirectory) against an agentId whose {agentsDataRoot}/{agentId} is a regular file, symlink, or other non-directory entry.","commonSituations":"A symlink substituted for the agent dir (tampering or sync placeholder); a file created at the directory path by a buggy tool; restore from backup that collapsed a dir into a file; filesystem corruption.","solutions":["Inspect the path: `ls -la <agentDataPath>` to confirm whether it is a file/symlink/device.","If it is not legitimate agent data, remove the offending entry and let the app recreate the directory.","Restore the agent data directory from a known-good backup if real data is involved.","Prevent external processes from replacing directories with symlinks/files under the data root."],"exampleFix":"// before: agent data root path is a symlink\nappData/agents/<id> -> /elsewhere\n\n// after: real directory\nrm appData/agents/<id>\n// app recreates a real directory on next ensureAgentDataDirectory()","handlingStrategy":"try-catch","validationCode":"import { lstat } from 'node:fs/promises'\nasync function isRealDir(p: string): Promise<boolean> {\n  try {\n    const s = await lstat(p)\n    return s.isDirectory() && !s.isSymbolicLink()\n  } catch {\n    return false\n  }\n}\nif (!(await isRealDir(agentDataPath))) {\n  throw new Error(`Agent data path is not a real directory: ${agentDataPath}`)\n}","typeGuard":"function isRealDirectory(stat: import('node:fs').Stats): boolean {\n  return stat.isDirectory() && !stat.isSymbolicLink()\n}","tryCatchPattern":"try {\n  await assertAgentDataDirectory(root, agentId)\n} catch (e) {\n  if (e instanceof Error && /must be a real directory/.test(e.message)) {\n    // mark agent data store corrupt; offer user a reset\n  } else throw e\n}","preventionTips":["Do not replace agent directories with symlinks or files.","Keep the data root off synced storage.","Validate integrity on startup before acting on agent data."],"tags":["filesystem","security","symlink","agents","integrity"],"backgroundTag":null,"analyzedSha":"726446b54cd69ffe51a276638672f6d95ca0768c","analyzedAt":"2026-08-12T17:30:37.448Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}