CherryHQ/cherry-studio · critical · Error
Agent storage path contains a symbolic link: ${current}
Error message
Agent storage path contains a symbolic link: ${current} What it means
Thrown by assertAgentStoragePath while walking each segment of the relative path from root to target: if any intermediate path component is a symbolic link (detected via lstat, which does not follow it), the walk aborts. This prevents a symlink planted inside the managed tree from redirecting a write outside the root (a classic TOCTOU/traversal escalation).
Source
Thrown at src/main/ai/agents/agentDataDirectory.ts:64
const root = asAbsolutePath(path.resolve(agentsDataRoot))
const target = asAbsolutePath(path.resolve(targetPath))
if (target !== root && !isPathInside(target, root)) {
throw new Error(`Agent storage path escapes its root: ${target}`)
}
const rootStat = await lstatIfExists(root)
if (!rootStat?.isDirectory || rootStat.isSymbolicLink) {
throw new Error(`Agent storage root must be a real directory: ${root}`)
}
let current = root
const relative = path.relative(root, target)
for (const segment of relative ? relative.split(path.sep) : []) {
current = asAbsolutePath(path.join(current, segment))
const currentStat = await lstatIfExists(current)
if (!currentStat) break
if (currentStat.isSymbolicLink) {
throw new Error(`Agent storage path contains a symbolic link: ${current}`)
}
if (current !== target && !currentStat.isDirectory) {
throw new Error(`Agent storage path parent is not a directory: ${current}`)
}
}
const [realRoot, realTarget] = await Promise.all([
resolveRealOrNearestExistingPath(root),
resolveRealOrNearestExistingPath(target)
])
if (realTarget !== realRoot && !isPathInside(realTarget, realRoot)) {
throw new Error(`Agent storage path resolves outside its root: ${target}`)
}
}
/** Ensure a Data/Agents path is a real directory contained by the Agent storage root. */
export async function ensureAgentStorageDirectory(agentsDataRoot: string, targetPath: string): Promise<void> {
await ensureDir(asAbsolutePath(path.resolve(agentsDataRoot)))View on GitHub (pinned to 726446b54c)
Solutions
- Remove the offending symlink and replace it with a real directory/file as appropriate.
- Investigate how the symlink got there — a recurring cause indicates a process (sync, backup, agent logic) recreating it.
- Do not weaken the check to follow symlinks; the guard exists to prevent traversal escalation.
- Run a filesystem audit for symlinks under Data/Agents: find <agentsDataRoot> -type l.
Defensive patterns
Strategy: validation
Validate before calling
import { lstatIfExists } from './agentDataDirectory'
// Walk root..target and reject any symlink segment
for (const seg of path.relative(root, target).split(path.sep)) {
current = path.join(current, seg)
const st = await lstatIfExists(current)
if (st?.isSymbolicLink) throw new Error(`Refusing: '${current}' is a symlink inside agents root`)
} Prevention
- Do not place symlinks inside the Data/Agents tree.
- Periodically audit for symlinks under the agents root (find <root> -type l).
- Investigate any tool (sync/backup/agent logic) that recreates links inside the data folder.
When it happens
Trigger: A symlink exists anywhere along the path between Data/Agents and the target (e.g. Data/Agents/<agentId>/memory is a symlink to /tmp). A compromised or misconfigured agent data folder contains a link; a backup restore introduced links; an external tool created a symlinked subdirectory.
Common situations: User or another process created a symlink inside the agent data tree; a migration/sync tool preserved links; a malicious or buggy agent wrote a symlink; cross-platform sync (e.g. cloud drive) materialized links.
Related errors
- Agent storage path resolves outside its root: ${target}
- Agent storage path escapes its root: ${target}
- Agent storage root must be a real directory: ${root}
- Agent storage directory must be a real directory: ${targetPa
- Invalid agent id for data directory: ${agentId}
AI-assisted analysis of CherryHQ/cherry-studio@726446b54c (2026-08-12).
Data as JSON: /api/errors/c473256aece9a1b9.
Report an issue: GitHub.