stablyai/orca · warning · Error
pending host credential cleanup storage unreadable
Error message
pending host credential cleanup storage unreadable
What it means
The pending host-credential-cleanup durable queue (AsyncStorage key 'orca:pending-host-credential-cleanups') could not be read or parsed during a read-modify-write mutation. mutatePendingIds calls readPendingIdsForMutation, which returns { ok: false } when AsyncStorage.getItem throws or JSON.parse yields a non-array. The mutation refuses to proceed because treating unreadable storage as [] would silently wipe durable pending cleanup IDs (orphaning keychain tokens).
Source
Thrown at mobile/src/transport/host-credential-cleanup.ts:100
async function loadPendingCleanupState(): Promise<PendingHostCredentialCleanup> {
await pendingMutation
const result = await readPendingIdsForMutation()
const fallback = [...unrecordedPendingIds]
if (!result.ok) {
// Why: durable queue unreadable — only the session-scoped fallback is
// known. Report unreadable so callers can surface a retry rather than
// pretend the queue is empty.
return { ids: [...new Set(fallback)], storageUnreadable: true }
}
return { ids: [...new Set([...result.ids, ...fallback])], storageUnreadable: false }
}
async function mutatePendingIds(update: (ids: string[]) => string[]): Promise<void> {
const mutation = pendingMutation.then(async () => {
const current = await readPendingIdsForMutation()
if (!current.ok) {
throw new Error('pending host credential cleanup storage unreadable')
}
const next = update(current.ids)
if (sameIdList(current.ids, next)) {
return
}
await AsyncStorage.setItem(PENDING_STORAGE_KEY, JSON.stringify(next))
notifyPendingListeners()
})
pendingMutation = mutation.catch(() => {})
return mutation
}
async function addPendingId(hostId: string): Promise<void> {
await mutatePendingIds((ids) => (ids.includes(hostId) ? ids : [...ids, hostId]))
}
async function removePendingId(hostId: string): Promise<void> {
await mutatePendingIds((ids) => ids.filter((id) => id !== hostId))View on GitHub (pinned to 1136503c6a)
Solutions
- Do NOT catch-and-treat-as-empty — that orphans keychain tokens. Surface a 'pending cleanup unknown' state (the loadPendingCleanupState path already sets storageUnreadable: true).
- Offer a manual 'retry cleanup' action in Settings (retryPendingHostCredentialCleanups).
- If corrupt JSON is confirmed, prompt the user to reset the cleanup queue only after confirming no orphaned tokens remain.
- Check AsyncStorage initialization and available storage space on the device.
Defensive patterns
Strategy: try-catch
Try / catch
try {
await recordHostCredentialCleanupIntent(hostId)
} catch (e) {
if (e.message === 'pending host credential cleanup storage unreadable') {
// Surface 'pending cleanup unknown' in Settings; offer manual retry
markUnrecordedPending(hostId)
}
} Prevention
- Never suppress this as empty — that orphans keychain tokens. Always surface storageUnreadable.
- Use the session-scoped unrecordedPendingIds fallback (markUnrecordedPending) so Settings can still offer retry.
- Check AsyncStorage health and device storage space when this recurs.
- Call retryPendingHostCredentialCleanups from Settings to re-attempt durable queue operations.
When it happens
Trigger: AsyncStorage.getItem rejects (native storage I/O failure); the stored JSON is corrupt (partial write after a crash); the parsed value is valid JSON but not an array (schema drift); AsyncStorage module not initialized in the JS engine.
Common situations: App crashed mid-write leaving truncated JSON; React Native upgrade broke AsyncStorage; storage quota exceeded; test environment without AsyncStorage polyfill; Hermes serialization edge case producing non-array JSON.
Related errors
- host list storage unreadable
- mobile relay host overlay storage unreadable
- pairing keychain presence record is invalid
- Could not read macOS Keychain item ${service}/${account}.
- Cannot capture current Claude Keychain credentials
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/179e4df0736fe68e.
Report an issue: GitHub.