stablyai/orca · error · Error

A different rollout already occupies the real-home target pa

Error message

A different rollout already occupies the real-home target path.

What it means

Thrown by assertMatchingExistingTarget when a link/copy hit EEXIST but the existing target file is not the same rollout as the source. The guard checks: target must be a regular file (not symlink), same size, and either same dev/ino (same hardlink) or identical sha256 digest. Any mismatch means a different rollout already occupies that path, so overwriting would corrupt resume provenance.

Source

Thrown at src/main/codex/codex-legacy-session-resume.ts:190

    failedHealAuditRecords: 0
  }
  await appendCodexSessionHealAuditRecord(
    createCodexSessionBackfillAuditWriter(auditLogPath),
    summary,
    { action: 'targeted-resume', source: sourcePath, target: targetPath }
  )
}

async function assertMatchingExistingTarget(sourcePath: string, targetPath: string): Promise<void> {
  const [sourceStat, targetStat] = await Promise.all([lstat(sourcePath), lstat(targetPath)])
  if (
    !targetStat.isFile() ||
    targetStat.isSymbolicLink() ||
    sourceStat.size !== targetStat.size ||
    ((sourceStat.dev !== targetStat.dev || sourceStat.ino !== targetStat.ino) &&
      (await fileDigest(sourcePath)) !== (await fileDigest(targetPath)))
  ) {
    throw new Error('A different rollout already occupies the real-home target path.')
  }
}

async function fileDigest(filePath: string): Promise<string> {
  const hash = createHash('sha256')
  for await (const chunk of createReadStream(filePath)) {
    hash.update(chunk as Buffer)
  }
  return hash.digest('hex')
}

function isDatedRolloutRelativePath(relativePath: string): boolean {
  if (!relativePath || relativePath.startsWith('..') || resolve(relativePath) === relativePath) {
    return false
  }
  const parts = relativePath.split(sep)
  return (
    parts.length === 4 &&

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Compare the existing target and source: ls -l and sha256sum both — if they genuinely differ, decide which rollout is canonical.
  2. Remove or rename the stale target file, then retry resume.
  3. If the target is a symlink, replace it with the correct regular file.
  4. Audit who else writes into paths.systemSessionsRoot to prevent future collisions.
  5. Do NOT blindly delete — confirm the existing file is not the wanted rollout first.
Defensive patterns

Strategy: validation

Validate before calling

import { lstat } from 'node:fs/promises'
import { createHash } from 'node:crypto'
async function targetMatchesSource(sourcePath: string, targetPath: string): Promise<boolean> {
  const [s, t] = await Promise.all([lstat(sourcePath), lstat(targetPath)])
  if (!t.isFile() || t.isSymbolicLink() || s.size !== t.size) return false
  if (s.dev === t.dev && s.ino === t.ino) return true // same hardlink
  // else compare sha256 digests
  return (await digest(sourcePath)) === (await digest(targetPath))
}

Try / catch

try {
  await prepareLegacySharedCodexSessionResume(args, options)
} catch (error) {
  if (error instanceof Error && error.message === 'A different rollout already occupies the real-home target path.') {
    // prompt user to resolve the conflicting target; do not auto-overwrite
  } else throw error
}

Prevention

When it happens

Trigger: A prior resume installed a different rollout at the same target path; two different rollouts hash to the same dated path after a clock/path collision; the existing file was truncated/modified; the target is a symlink or non-regular file.

Common situations: A rollout was overwritten by another tool; dedup collision in a shared home; partial previous write left a wrong-size file; user manually placed a different file at the target.

Related errors


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