stablyai/orca · warning · RuntimeUploadSymlinkError
Symlink not allowed in '${displayPath}'
Error message
Symlink not allowed in '${displayPath}' What it means
Thrown as RuntimeUploadSymlinkError by stageFileEntry() when a staged single file lstat()s as a symbolic link. stageFileEntry is used both for child files during directory staging and for a single-file source in stageOneSourceForRuntimeUpload. The dedicated error class is caught upstairs and converted to { status: 'skipped', reason: 'symlink' }, so a symlinked top-level file is skipped rather than having its target uploaded.
Source
Thrown at src/main/ipc/filesystem-mutations.ts:580
})
totalBytes += stagedFile.byteLength
entries.push(stagedFile.entry)
}
}
await visit(rootPath)
return entries
}
async function stageFileEntry(
filePath: string,
relativePath: string,
options?: { rootRealPath?: string; totalBytesBefore?: number }
): Promise<{ entry: StagedExternalImportEntry; byteLength: number }> {
const statResult = await lstat(filePath)
const displayPath = normalizeRelativeUploadPath(relativePath)
if (statResult.isSymbolicLink()) {
throw new RuntimeUploadSymlinkError(`Symlink not allowed in '${displayPath}'`)
}
if (!statResult.isFile()) {
throw new Error(`Unsupported file type in '${displayPath}'`)
}
if (options?.rootRealPath) {
await assertRealPathInsideRoot(options.rootRealPath, filePath, displayPath)
}
const initialTotalBytes =
options?.totalBytesBefore === undefined
? statResult.size
: options.totalBytesBefore + statResult.size
assertRemoteUploadBudget(relativePath, statResult.size, initialTotalBytes)
const fileHandle = await open(filePath, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0))
try {
const openedStat = await fileHandle.stat()
if (!openedStat.isFile()) {
throw new Error(`Unsupported file type in '${displayPath}'`)
}View on GitHub (pinned to 1136503c6a)
Solutions
- Select the real target file instead of the symlink, or copy the target content to a regular file and upload that.
- Resolve symlinks in the selection UI before staging so only regular files are passed.
- Treat the skipped result as expected and inform the user that symlinked files are not uploaded.
Defensive patterns
Strategy: try-catch
Validate before calling
// Detect a symlinked single-file source before staging
import { lstat } from 'node:fs/promises'
async function isSymlinkFile(p: string): Promise<boolean> {
try { return (await lstat(p)).isSymbolicLink() } catch { return false }
} Try / catch
const res = await stageOneSourceForRuntimeUpload(src)
if (res.status === 'skipped' && res.reason === 'symlink') {
// tell the user the selected file is a symlink; offer to upload its real target
} Prevention
- Resolve symlinked selections to their real targets in the UI before staging.
- Inform users that symlinked files are skipped, not followed, by runtime upload.
- Replace linked assets with copies if their content must be uploaded.
When it happens
Trigger: A single-file source passed to runtime-upload staging lstat()s as a symlink (isSymbolicLink()), or a child file staged from a directory is a symlink; stageFileEntry rejects it before opening.
Common situations: User selected a symlinked file (a linked shortcut) for upload; a tree contains symlinked dotfiles or linked assets; tooling created symlinks to shared files that ended up in the selection.
Related errors
- Symlink not allowed in '${normalizeRelativeUploadPath(relati
- Symlink not allowed in '${childRelativePath}'
- Unsupported file type in '${normalizeRelativeUploadPath(rela
- Unsupported file type in '${childRelativePath}'
- Unsupported file type in '${displayPath}'
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/7ef0e36a7e031bcb.
Report an issue: GitHub.