stablyai/orca · error · Error
Codex reset attempt journal is unreadable
Error message
Codex reset attempt journal is unreadable
What it means
Thrown by `parseAttempt` in the codex-reset-credit attempt journal when `JSON.parse(raw)` throws — the persisted AsyncStorage value under the attempt key is not valid JSON. The journal stores one durable reset attempt per stable account scope so a lost provider-mutation response can be made idempotent; a corrupt entry cannot be trusted and is rejected wholesale.
Source
Thrown at mobile/src/storage/codex-reset-attempt-journal.ts:101
function stableAccountScopesEqual(
left: CodexResetCreditExpectedScope,
right: CodexResetCreditExpectedScope
): boolean {
return (
left.target.runtime === right.target.runtime &&
left.target.wslDistro === right.target.wslDistro &&
left.accountId === right.accountId &&
left.accountRevision === right.accountRevision
)
}
function parseAttempt(raw: string, identity: AttemptIdentity): CodexResetAttempt {
let value: unknown
try {
value = JSON.parse(raw)
} catch {
throw new Error('Codex reset attempt journal is unreadable')
}
const result = CodexResetAttemptSchema.safeParse(value)
if (
!result.success ||
result.data.hostId !== identity.hostId ||
!stableAccountScopesEqual(result.data.expectedScope, identity.expectedScope)
) {
throw new Error('Codex reset attempt journal is unreadable')
}
return result.data
}
async function withScopeMutation<T>(
identity: AttemptIdentity,
action: () => Promise<T>
): Promise<T> {
const key = storageKey(identity)
const previous = scopeMutations.get(key) ?? Promise.resolve()View on GitHub (pinned to 1136503c6a)
Solutions
- Clear the corrupt attempt key so a fresh idempotency key is generated on next reset (acceptable once the authoritative response is confirmed).
- Run `clearCodexResetAttemptAfterAuthoritativeResponse` only after confirming no in-flight reset RPC depends on the old key.
- Reproduce under the same AsyncStorage mock to find what wrote the non-JSON value.
- Ensure no other code path writes raw non-JSON under the `orca:codex-reset-credit-attempt:v1:` prefix.
Defensive patterns
Strategy: try-catch
Try / catch
// parseAttempt already throws; callers via getOrCreate/clear should treat an
// unreadable journal as 'start fresh' once no in-flight reset depends on it.
try {
return parseAttempt(raw, identity)
} catch {
// corrupt JSON — safe to overwrite with a new attempt if authoritative response confirmed
await AsyncStorage.removeItem(key)
return createFreshAttempt(identity)
} Prevention
- Write the journal atomically (the code already serialises via withScopeMutation).
- Never write non-JSON under the orca:codex-reset-credit-attempt:v1: prefix.
- On schema/version changes, bump the prefix version so corrupt/old entries are ignored.
When it happens
Trigger: Reading the codex-reset attempt key (`orca:codex-reset-credit-attempt:v1:<digest>`) where AsyncStorage returns a string that is not parseable JSON — partial write, external tampering, or storage corruption from a crash mid-write.
Common situations: App was killed mid-`setItem` leaving a truncated string; a storage migration wrote a non-JSON value under the same key prefix; AsyncStorage backend (SQLite/file) corruption on a specific OS version; manual debug writes.
Related errors
- Codex reset attempt idempotency key is invalid
- Codex reset attempt journal identity changed
- Session view overrides could not be read
- mobile relay host overlay storage unreadable
- Artifact share records could not be read safely.
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/9197714ac32dfa86.
Report an issue: GitHub.