stablyai/orca · error · Error
Upload source changed while being inspected: ${sourcePath}
Error message
Upload source changed while being inspected: ${sourcePath} What it means
Thrown by captureLocalUploadRoot() during SSH directory import. It compares the caller-supplied sourceStat (lstat of the unresolved source) against a fresh lstat of realpath(source). If the inode (ino) or device (dev) identity parts both read as known-and-different, or the resolved real path is no longer a directory, the source is treated as replaced mid-inspection. This is a TOCTOU guard: between the initial lstat and the realpath+lstat the directory was swapped, moved, bind-mounted, or changed type.
Source
Thrown at src/main/ipc/filesystem-import-ssh-directory.ts:17
import { lstat, readdir, realpath } from 'node:fs/promises'
import { isAbsolute, join, relative, sep } from 'node:path'
import type { FileUploadSession, IFilesystemProvider } from '../providers/types'
import { assertSafeRemotePathSegment, type RemotePathFlavor } from '../ssh/ssh-remote-platform'
export async function captureLocalUploadRoot(
sourcePath: string,
sourceStat: Awaited<ReturnType<typeof lstat>>
): Promise<string> {
const rootRealPath = await realpath(sourcePath)
const rootRealStat = await lstat(rootRealPath)
if (
statIdentityPartChanged(sourceStat.ino, rootRealStat.ino) ||
statIdentityPartChanged(sourceStat.dev, rootRealStat.dev) ||
!rootRealStat.isDirectory()
) {
throw new Error(`Upload source changed while being inspected: ${sourcePath}`)
}
return rootRealPath
}
export async function preScanSshImportDirectory(
dirPath: string,
remotePathFlavor: RemotePathFlavor
): Promise<boolean> {
const entries = await readdir(dirPath, { withFileTypes: true })
for (const entry of entries) {
assertSafeRemotePathSegment(entry.name, remotePathFlavor)
if (entry.isSymbolicLink()) {
return true
}
if (entry.isDirectory()) {
const childPath = join(dirPath, entry.name)
if (await preScanSshImportDirectory(childPath, remotePathFlavor)) {
return trueView on GitHub (pinned to 1136503c6a)
Solutions
- Re-select the source directory and retry the import promptly, without modifying it during the scan.
- Pause build/watchdog processes that may rewrite the directory during import.
- If on a network filesystem with unstable ino/dev, copy the source to a local stable path first and import that.
Defensive patterns
Strategy: retry
Validate before calling
// Re-validate identity immediately before captureLocalUploadRoot
import { lstat, realpath } from 'node:fs/promises'
async function isStableDir(p: string, prev: { ino: number; dev: number }): Promise<boolean> {
const real = await realpath(p)
const s = await lstat(real)
return s.isDirectory() && (prev.ino === 0 || s.ino === 0 || s.ino === prev.ino) &&
(prev.dev === 0 || s.dev === 0 || s.dev === prev.dev)
} Try / catch
try {
await importExternalPathsSsh([src], dest, connId, opts)
} catch (e) {
if (e instanceof Error && /changed while being inspected/.test(e.message)) {
// re-select the source and retry once it is stable
} else throw e
} Prevention
- Do not modify the selected source directory while the import scan runs.
- On network filesystems with unstable ino/dev, copy the source to a local stable path first.
- Pause build/watch tools that rewrite the directory during import.
When it happens
Trigger: importExternalPathsSsh is called for a directory source; between the initial lstat and captureLocalUploadRoot the directory is renamed/replaced, or its realpath now resolves to a non-directory, or the filesystem (network/macOS fid instability) reports a different ino/dev.
Common situations: Another process or the user moved/replaced the dropped directory while the import dialog/scan was running; a build tool regenerated the directory; network filesystems where ino/dev are not stable across calls; the source was a symlink target that changed underneath.
Related errors
- No SSH connection for "${connectionId}"
- SSH connection is not active — please reconnect and try agai
- Cannot download a directory
- Couldn't verify the SSH connection. Reconnect the host and t
- No Claude credentials found in ${resolvedDir}. Run `claude l
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/535674b4b5a00a89.
Report an issue: GitHub.