stablyai/orca · error · Error
Codex reset attempt journal identity changed
Error message
Codex reset attempt journal identity changed
What it means
Thrown by `clearCodexResetAttemptAfterAuthoritativeResponse` when the stored attempt's `idempotencyKey` does not equal the `identity.idempotencyKey` passed in. The clear is meant to run only after the authoritative provider response confirms a specific attempt completed; a mismatch means a different/older attempt is in the journal (a newer reset started, or the wrong key was supplied) and clearing it would delete state still needed for in-flight idempotency.
Source
Thrown at mobile/src/storage/codex-reset-attempt-journal.ts:173
// Why: the key must survive a committed provider mutation whose response is
// lost; no reset RPC may start until this write has completed successfully.
await AsyncStorage.setItem(key, JSON.stringify(attempt))
return attempt
})
}
export async function clearCodexResetAttemptAfterAuthoritativeResponse(
identity: AttemptIdentity & { idempotencyKey: string }
): Promise<void> {
return withScopeMutation(identity, async () => {
const key = storageKey(identity)
const raw = await AsyncStorage.getItem(key)
if (raw === null) {
return
}
const current = parseAttempt(raw, identity)
if (current.idempotencyKey !== identity.idempotencyKey) {
throw new Error('Codex reset attempt journal identity changed')
}
await AsyncStorage.removeItem(key)
})
}
/** Test-only: drain in-memory queues while preserving the durable storage mock. */
export function resetCodexResetAttemptJournalForTests(): void {
scopeMutations.clear()
}
View on GitHub (pinned to 1136503c6a)
Solutions
- Pass the exact `idempotencyKey` returned by `getOrCreateCodexResetAttempt` that corresponds to the response being confirmed.
- If a new reset superseded the old one, do not clear — the new attempt still needs its journal entry.
- Ensure only one reset flow is in flight per account scope at a time (the `withScopeMutation` queue serializes, but distinct callers should coordinate keys).
- Capture the idempotency key at attempt-creation time and thread the same value through to the clear call.
Defensive patterns
Strategy: validation
Validate before calling
// Thread the exact key from creation through to clear.
const attempt = await getOrCreateCodexResetAttempt(identity)
// ...perform reset with attempt.idempotencyKey...
await clearCodexResetAttemptAfterAuthoritativeResponse({ ...identity, idempotencyKey: attempt.idempotencyKey }) Try / catch
try {
await clearCodexResetAttemptAfterAuthoritativeResponse({ ...identity, idempotencyKey })
} catch (err) {
if (err instanceof Error && err.message === 'Codex reset attempt journal identity changed') {
// a newer attempt superseded this one — do not clear; leave journal intact
} else throw err
} Prevention
- Capture the idempotency key at creation and pass the same instance to clear.
- Prevent concurrent reset flows per account scope so keys don't rotate mid-flight.
- Treat a mismatch as 'do not clear' — the current attempt still needs its journal entry.
When it happens
Trigger: Calling clear with an `idempotencyKey` that differs from the one persisted: a second reset created a new attempt (new key) between the original reset and this clear, or the caller is clearing with a stale/incorrect key.
Common situations: User retried the reset before the first response arrived, generating a new idempotency key; the clear callback fired with an old captured key after a key rotation; concurrent reset attempts racing through the serialized `withScopeMutation` queue.
Related errors
- Codex reset attempt journal is unreadable
- Codex reset attempt idempotency key is invalid
- mobile relay pairing recovery pending
- A previous reset attempt for this target still has an unknow
- Terminal input is locked by another client.
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/49366716118d2543.
Report an issue: GitHub.