stablyai/orca · error · Error

File changed during import: '${basename(srcPath)}'

Error message

File changed during import: '${basename(srcPath)}'

What it means

Thrown in copyLocalFileNoFollow after opening the source with O_NOFOLLOW. The post-open fstat (openedStat) is compared against the pre-open lstat (beforeOpenStat): size, inode, and device must all match. If any differ, the file was swapped between the lstat and the open. Streaming from the O_NOFOLLOW handle pins the authorized file identity, but this check ensures the handle actually refers to the file that was validated.

Source

Thrown at src/main/ipc/filesystem-mutations.ts:738

  let destinationCreated = false
  const sourceHandle = await open(srcPath, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0))
  let destinationHandle: Awaited<ReturnType<typeof open>> | null = null
  try {
    const openedStat = await sourceHandle.stat()
    if (
      !openedStat.isFile() ||
      (typeof beforeOpenStat.size === 'number' && openedStat.size !== beforeOpenStat.size) ||
      (typeof beforeOpenStat.ino === 'number' &&
        beforeOpenStat.ino !== 0 &&
        openedStat.ino !== 0 &&
        openedStat.ino !== beforeOpenStat.ino) ||
      (typeof beforeOpenStat.dev === 'number' &&
        beforeOpenStat.dev !== 0 &&
        openedStat.dev !== 0 &&
        openedStat.dev !== beforeOpenStat.dev)
    ) {
      throw new Error(`File changed during import: '${basename(srcPath)}'`)
    }
    // Why: copyFile(path, path) would follow a source symlink if the source is
    // swapped after validation. Streaming from an O_NOFOLLOW handle keeps the
    // authorized file identity pinned for the copy.
    destinationHandle = await open(dstPath, 'wx')
    destinationCreated = true
    await pipeline(sourceHandle.createReadStream(), destinationHandle.createWriteStream())
  } catch (error) {
    if (destinationCreated) {
      await unlink(dstPath).catch(() => {})
    }
    throw error
  } finally {
    await sourceHandle.close().catch(() => {})
    await destinationHandle?.close().catch(() => {})
  }
}

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Ensure the source file is not being modified during the import.
  2. Copy the file to a stable local path before importing.
  3. Retry the import after the source has stabilized.

Example fix

// before: import a file that a build tool is atomically replacing
// after: snapshot the file first
//   cp /project/output.bin /tmp/stable.bin
//   import /tmp/stable.bin
Defensive patterns

Strategy: retry

Try / catch

try {
  await importLocalSource(sourcePath, destDir)
} catch (error) {
  if (error instanceof Error && error.message.includes('File changed during import')) {
    showUserWarning('The source file changed during import. Ensure it is stable and retry.')
    return
  }
  throw error
}

Prevention

When it happens

Trigger: Between the beforeOpenStat lstat and the O_NOFOLLOW open, the source file is replaced, truncated, or moved such that its size, inode, or device number changes. The open succeeds but fstat reports a different identity.

Common situations: A file being rewritten by an editor or build tool during import. Atomic file replacement (write-to-temp-then-rename) happening between lstat and open. Importing from a network filesystem where inode/device mapping is not stable.

Related errors


AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12). Data as JSON: /api/errors/48447994b7203973. Report an issue: GitHub.