stablyai/orca · error · Error
Path escaped upload root during staging: '${displayPath}'
Error message
Path escaped upload root during staging: '${displayPath}' What it means
Thrown by assertRealPathInsideRoot during remote upload directory staging. The function resolves the candidate path with realpath and checks whether the resolved path is still within the upload root. If the relative path from root to the candidate starts with '..' or is absolute, the path escaped the root boundary. This catches cases where an intermediate directory component was replaced (e.g., a directory swapped for a symlink or bind mount) after the pre-scan, allowing the resolved path to point outside the authorized subtree.
Source
Thrown at src/main/ipc/filesystem-mutations.ts:641
}
} finally {
await fileHandle.close()
}
}
async function assertRealPathInsideRoot(
rootRealPath: string,
candidatePath: string,
displayPath: string
): Promise<void> {
const candidateRealPath = await realpath(candidatePath)
const relativeToRoot = relative(rootRealPath, candidateRealPath)
// Why: `..name` is a valid child path; only `..` and `../...` escape.
if (
relativeToRoot !== '' &&
(relativeToRoot === '..' || relativeToRoot.startsWith(`..${sep}`) || isAbsolute(relativeToRoot))
) {
throw new Error(`Path escaped upload root during staging: '${displayPath}'`)
}
}
function assertRemoteUploadBudget(
relativePath: string,
fileBytes: number,
totalBytes: number
): void {
if (fileBytes > REMOTE_IMPORT_MAX_FILE_BYTES) {
throw new Error(`'${relativePath}' is too large for remote import`)
}
if (totalBytes > REMOTE_IMPORT_MAX_TOTAL_BYTES) {
throw new Error('Remote import is too large')
}
}
function normalizeRelativeUploadPath(path: string): string {
return path.replace(/[\\/]+/g, '/').replace(/^\/+/, '')View on GitHub (pinned to 1136503c6a)
Solutions
- Examine the flagged displayPath and its parent directories for symlinks or mount points using `readlink -f` or `find -type l`.
- Ensure the source tree does not contain mount points or symlinks to external locations.
- Copy the subtree to a clean temp directory with `cp -r --no-dereference` excluded, then import from there.
Example fix
// before: import /shared/project where /shared/project/lib -> /usr/lib // after: remove or resolve the escaping link // rm /shared/project/lib // cp -r /actual/lib /shared/project/lib
Defensive patterns
Strategy: validation
Validate before calling
const { realpath } = await import('node:fs/promises')
const { relative, isAbsolute, sep } = await import('node:path')
async function assertPathInsideRoot(rootReal: string, candidate: string): Promise<void> {
const resolved = await realpath(candidate)
const rel = relative(rootReal, resolved)
if (rel !== '' && (rel === '..' || rel.startsWith(`..${sep}`) || isAbsolute(rel))) {
throw new Error(`Path escapes root: ${candidate} -> ${resolved}`)
}
} Try / catch
try {
await stageRemoteImport(sourcePath)
} catch (error) {
if (error instanceof Error && error.message.includes('Path escaped upload root')) {
showUserError('The source tree contains a path that escapes the import root. Check for mount points or replaced directories.')
return
}
throw error
} Prevention
- Check source trees for mount points and bind mounts with `mountpoint` or `findmnt`.
- Run `find <source> -type l` to detect symlinks that could resolve outside the root.
- Import from a clean copy that has no external links or mounts.
When it happens
Trigger: During stageDirectoryEntries traversal, realpath on a child path resolves outside rootRealPath. An intermediate directory in the tree was replaced by a symlink or mount point between the pre-scan and the per-file staging, causing the canonical path to escape the upload root.
Common situations: Importing a directory tree that contains mount points or bind mounts pointing outside the root. A shared or adversarial workspace where a sibling process replaces a directory with a symlink during import. Linux /proc or /sys style virtual filesystem entries that resolve outside the apparent tree.
Related errors
- File changed during upload staging: '${displayPath}'
- Symlink not allowed in '${entry.name}'
- Symlink not allowed in '${basename(srcPath)}'
- pet.json must not be a symlink.
- Managed Claude auth child file is not owned by Orca.
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/e3ff1b0df542b0fa.
Report an issue: GitHub.