stablyai/orca · warning · Error

Codex hooks.json changed while Orca prepared its trust repai

Error message

Codex hooks.json changed while Orca prepared its trust repair

What it means

Thrown by assertHooksJsonGeneration when the raw bytes of the user's real-home hooks.json (or its resolved write path) changed between the initial read (readHooksJsonWithRaw) and the pre-write generation check. Orca snapshots the file, prepares an in-memory mutation, then re-reads on disk before writing; a concurrent external save (user's editor, another codex instance) invalidates the snapshot to avoid clobbering newer content with a stale parse.

Source

Thrown at src/main/codex/codex-real-home-hook-install.ts:81

function getRealHomeConfigTomlPath(): string {
  return join(getSystemCodexHomePath(), 'config.toml')
}

/** Orca-side state dir; nothing extra is ever written into the user's ~/.codex. */
function getRealHomeHookStateDir(userDataPath: string): string {
  return join(userDataPath, 'codex-real-home-hooks')
}

function assertHooksJsonGeneration(
  hooksJsonPath: string,
  hooksWritePath: string,
  expectedRaw: string | null
): void {
  const currentRaw = existsSync(hooksJsonPath) ? readFileSync(hooksJsonPath, 'utf-8') : null
  if (currentRaw !== expectedRaw || resolveHooksJsonWritePath(hooksJsonPath) !== hooksWritePath) {
    // Why: the pre-mutation RPC can overlap a user's editor save. Abort rather
    // than atomically replacing a newer file with the stale parsed snapshot.
    throw new Error('Codex hooks.json changed while Orca prepared its trust repair')
  }
}

/**
 * Ensures the real-home hook state matches the settings: installs and trusts
 * the Orca status hook when enabled, sweeps it when opted out. Idempotent and
 * synchronous (launch prep); repeat calls are cheap — an unchanged hooks.json
 * write no-ops and a valid grant ledger skips the RPC session entirely.
 * Never throws: any failure logs and leaves the host on the managed lane.
 */
export function ensureRealHomeCodexHookState(args: {
  hooksEnabled: boolean
  userDataPath: string
}): RealHomeCodexHookLane {
  // Why: the grant client caches failed probes, but mutating and rolling back
  // hooks.json before consulting it still adds synchronous work to every pane.
  if (args.hooksEnabled && currentLane === 'unavailable' && Date.now() < installRetryAfterMs) {
    return currentLane

View on GitHub (pinned to 1136503c6a)

Solutions

  1. Close editors/tools editing ~/.codex/hooks.json during launch, then retry — ensureRealHomeCodexHookState retries on the next pane.
  2. If using a hook-manager extension, pause it or coordinate so only one writer mutates hooks.json at a time.
  3. Confirm hooks.json is not a symlink whose target changes (resolveHooksJsonWritePath must be stable).
  4. Rely on the managed-home fallback: a failed install leaves currentLane='unavailable' and status still works.
  5. Re-enable real-home hooks after the external edit completes.
Defensive patterns

Strategy: retry

Validate before calling

// Minimize the window between snapshot and write; avoid long async gaps in writeHooks.
// Before install, warn the user if hooks.json mtime changed very recently:
import { statSync } from 'node:fs'
const mtimeMs = statSync(hooksJsonPath).mtimeMs
if (Date.now() - mtimeMs < 2000) {
  // likely being edited; defer the install to the next pane launch
}

Type guard

function isHooksJsonGenerationError(error: unknown): boolean {
  return error instanceof Error && error.message === 'Codex hooks.json changed while Orca prepared its trust repair'
}

Try / catch

try {
  ensureRealHomeCodexHookState({ hooksEnabled: true, userDataPath })
} catch (error) {
  if (isHooksJsonGenerationError(error)) {
    // non-fatal: managed lane continues; retry on next pane launch
    currentLane = 'unavailable'
  } else throw error
}

Prevention

When it happens

Trigger: A user saved hooks.json in their editor between Orca's snapshot read and the writeHooks callback; another Orca process or codex TUI rewrote hooks.json; the resolved write path (symlink target via resolveHooksJsonWritePath) shifted because the symlink changed.

Common situations: User actively editing hooks.json while Orca does launch-prep hook install; two Orca windows racing; a hook-manager extension rewriting the file; the file is a symlink whose target was swapped.

Related errors


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