{"record":{"id":"c6c2f14e9df0dbc1","repo":"stablyai/orca","slug":"orca-relay-pairing-requires-a-native-secret-store","errorCode":null,"errorMessage":"Orca Relay pairing requires a native secret store","messagePattern":"Orca Relay pairing requires a native secret store","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"mobile/src/transport/mobile-relay-pairing-journal-store.ts","lineNumber":145,"sourceCode":"    const result = MobileRelayPairingJournalMetadataSchema.safeParse(JSON.parse(raw))\n    return result.success ? result.data : null\n  } catch {\n    return null\n  }\n}\n\nfunction parseSecrets(raw: string) {\n  try {\n    const result = MobileRelayPairingJournalSecretsSchema.safeParse(JSON.parse(raw))\n    return result.success ? result.data : null\n  } catch {\n    return null\n  }\n}\n\nfunction requireNativeSecretStore(): void {\n  if (Platform.OS === 'web') {\n    throw new Error('Orca Relay pairing requires a native secret store')\n  }\n}\n\n/** Test-only: drain the module mutation chain between cases. */\nexport function resetMobileRelayPairingJournalStoreForTests(): void {\n  journalMutation = Promise.resolve()\n  resetPairingKeychainForTests()\n}\n","sourceCodeStart":127,"sourceCodeEnd":154,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/transport/mobile-relay-pairing-journal-store.ts#L127-L154","documentation":"Thrown by requireNativeSecretStore when Platform.OS === 'web'. The pairing journal persists secrets to a native keychain (iOS Keychain / Android Keystore) that does not exist on web; save and load are refused on web targets.","triggerScenarios":"Calling saveMobileRelayPairingJournal or loadMobileRelayPairingJournal inside a web build (React Native Web / Expo web).","commonSituations":"Running the mobile transport module in a web target during development; importing the journal store on web via a shared entry point; SSR hitting the module.","solutions":["Guard the pairing flow behind a Platform.OS check at the caller and skip relay pairing on web.","Use a platform-specific entry point so the journal store is not imported on web.","Provide a web-appropriate credential path or surface 'relay pairing unavailable on web' in the UI."],"exampleFix":"// before\nimport { saveMobileRelayPairingJournal } from './mobile-relay-pairing-journal-store'\nawait saveMobileRelayPairingJournal(journal) // throws on web\n// after\nimport { Platform } from 'react-native'\nif (Platform.OS === 'web') {\n  throw new Error('relay pairing unavailable on this platform')\n}\nawait saveMobileRelayPairingJournal(journal)","handlingStrategy":"validation","validationCode":"import { Platform } from 'react-native'\nfunction assertNotWeb(): void {\n  if (Platform.OS === 'web') {\n    throw new Error('relay pairing unavailable on web')\n  }\n}\n// call assertNotWeb() before invoking save/load so the error is yours, not the store's","typeGuard":"import { Platform } from 'react-native'\nfunction supportsNativeSecretStore(): boolean {\n  return Platform.OS !== 'web'\n}","tryCatchPattern":null,"preventionTips":["Use platform-specific entry points so the journal store is not imported on web at all.","Gate the entire relay-pairing UI behind a platform capability check.","Run the transport module's tests under the native target, not the web target."],"tags":["platform","web","relay","pairing","native"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}