stablyai/orca · error
mobile relay host overlay storage unreadable
Error message
mobile relay host overlay storage unreadable
What it means
Thrown by readOverlaysForMutation when parseOverlays returns null: AsyncStorage holds a value under 'orca:mobile-relay:host-overlays:v2' that is not a JSON array (corrupt JSON or a non-array shape). The guard deliberately refuses to rewrite an unreadable namespace as an empty list, to avoid destroying relay recovery data during an unrelated mutation.
Source
Thrown at mobile/src/transport/mobile-relay-host-overlay-store.ts:33
const value = JSON.parse(raw) as unknown
if (!Array.isArray(value)) {
return null
}
return value.flatMap((item) => {
const result = MobileRelayHostOverlaySchema.safeParse(item)
return result.success ? [result.data] : []
})
} catch {
return null
}
}
async function readOverlaysForMutation(): Promise<MobileRelayHostOverlay[]> {
const overlays = parseOverlays(await AsyncStorage.getItem(OVERLAY_STORAGE_KEY))
if (!overlays) {
// Why: never rewrite an unreadable v2 namespace as an empty list; doing so
// would destroy relay recovery data during an unrelated host mutation.
throw new Error('mobile relay host overlay storage unreadable')
}
return overlays
}
async function mutateOverlays(
update: (overlays: MobileRelayHostOverlay[]) => MobileRelayHostOverlay[]
): Promise<void> {
const mutation = overlayMutation.then(async () => {
const current = await readOverlaysForMutation()
const next = update(current)
// Why: direct-only saves commonly have no overlay to remove; avoid a full
// AsyncStorage write when cleanup leaves the durable list unchanged.
if (next !== current) {
await AsyncStorage.setItem(OVERLAY_STORAGE_KEY, JSON.stringify(next))
}
})
overlayMutation = mutation.catch(() => {})
return mutationView on GitHub (pinned to 1136503c6a)
Solutions
- Read the raw value under the key (read-only) to confirm it is non-array/corrupt.
- If genuinely unrecoverable, explicitly remove the key once, accepting that relay overlays will rebuild from host discovery.
- Ensure every writer routes through MobileRelayHostOverlaySchema.parse so only valid v2 arrays are stored.
- Add a one-time repair migration that detects non-array JSON and either quarantines or clears it deliberately.
Defensive patterns
Strategy: try-catch
Validate before calling
import AsyncStorage from '@react-native-async-storage/async-storage'
async function isOverlayStorageReadable(): Promise<boolean> {
const raw = await AsyncStorage.getItem('orca:mobile-relay:host-overlays:v2')
if (raw === null) return true
try {
return Array.isArray(JSON.parse(raw))
} catch {
return false
}
} Try / catch
try {
await saveMobileRelayHostOverlay(overlay)
} catch (error) {
if (error instanceof Error && error.message === 'mobile relay host overlay storage unreadable') {
// deliberate one-time repair: quarantine the bad key, then retry
}
} Prevention
- Never write to the v2 overlay key except through MobileRelayHostOverlaySchema.parse-validated writers.
- Add a startup probe that reads the key and reports unreadable state before any mutation is attempted.
- Quarantine corrupt data into a separate key rather than silently clearing it.
When it happens
Trigger: Any call to saveMobileRelayHostOverlay or removeMobileRelayHostOverlay(s) while the v2 key contains non-array JSON: a string, an object, or truncated JSON from a crash mid-write.
Common situations: A previous app version wrote a non-array under the same key; AsyncStorage corruption from a crash during setItem; manual injection during testing; a partial migration left legacy data in the v2 namespace.
Related errors
- mobile relay pairing journal identity mismatch
- Codex reset attempt journal is unreadable
- Session view overrides could not be read
- pending host credential cleanup storage unreadable
- host list storage unreadable
AI-assisted analysis of stablyai/orca@1136503c6a (2026-08-12).
Data as JSON: /api/errors/f8731ccd743773b6.
Report an issue: GitHub.