{"record":{"id":"414a2b1feeaaf9fb","repo":"stablyai/orca","slug":"orca-relay-upgrade-state-requires-a-native-secret","errorCode":null,"errorMessage":"Orca Relay upgrade state requires a native secret store","messagePattern":"Orca Relay upgrade state requires a native secret store","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mobile/src/transport/mobile-relay-direct-upgrade-journal.ts","lineNumber":85,"sourceCode":"\nexport async function deleteMobileRelayDirectUpgradeJournal(hostId: string): Promise<void> {\n  if (Platform.OS === 'web') {\n    return\n  }\n  await deletePairingKeychainItem(journalKey(hostId))\n}\n\nfunction encodeBase64Url(value: Uint8Array): string {\n  let binary = ''\n  for (const byte of value) {\n    binary += String.fromCharCode(byte)\n  }\n  return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\nfunction requireNativeSecretStore(): void {\n  if (Platform.OS === 'web') {\n    throw new Error('Orca Relay upgrade state requires a native secret store')\n  }\n}\n","sourceCodeStart":67,"sourceCodeEnd":88,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/transport/mobile-relay-direct-upgrade-journal.ts#L67-L88","documentation":"Thrown by `requireNativeSecretStore` in the direct-upgrade journal module when `Platform.OS === 'web'`. Same rationale as the credential-bundle variant (error 449): the direct-upgrade journal — which holds a pending resume token and reqId — must live in the native keychain, and web has no secure equivalent, so read/write/delete of the journal is refused on web.","triggerScenarios":"Calling `readMobileRelayDirectUpgradeJournal` or `writeMobileRelayDirectUpgradeJournal` while `Platform.OS === 'web'`; web build pulling in the direct-upgrade module.","commonSituations":"Web target of the RN app; Storybook/Jest under web platform mock; shared import that reaches the upgrade journal from web code.","solutions":["Gate direct-upgrade journal access on `Platform.OS !== 'web'`.","On web, never invoke `upgradeDirectMobileRelay` — skip direct upgrade entirely.","In tests, set `Platform.OS` to a native value before exercising these functions."],"exampleFix":"// before\nimport { readMobileRelayDirectUpgradeJournal } from './mobile-relay-direct-upgrade-journal'\nconst j = await readMobileRelayDirectUpgradeJournal(hostId) // throws on web\n\n// after\nconst j = Platform.OS === 'web' ? null : await readMobileRelayDirectUpgradeJournal(hostId)","handlingStrategy":"type-guard","validationCode":"import { Platform } from 'react-native'\nif (Platform.OS === 'web') { /* skip direct upgrade entirely */ return null }","typeGuard":"function hasNativeSecretStore(): boolean { return Platform.OS !== 'web' }","tryCatchPattern":null,"preventionTips":["Never invoke upgradeDirectMobileRelay on web.","Gate journal read/write on Platform.OS !== 'web'.","Exclude the direct-upgrade module from web bundles."],"tags":["platform","web","storage","relay","upgrade"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}