{"record":{"id":"7651f3c990e87443","repo":"stablyai/orca","slug":"orca-relay-credentials-require-a-native-secret-sto","errorCode":null,"errorMessage":"Orca Relay credentials require a native secret store","messagePattern":"Orca Relay credentials require a native secret store","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"mobile/src/transport/mobile-relay-credential-bundle.ts","lineNumber":108,"sourceCode":"export async function writeMobileRelayCredentialBundle(\n  bundle: MobileRelayCredentialBundle\n): Promise<void> {\n  requireNativeSecretStore()\n  const validated = MobileRelayCredentialBundleSchema.parse(bundle)\n  markHostCredentialWrite(validated.hostId)\n  await writePairingKeychainItem(credentialKey(validated.hostId), JSON.stringify(validated))\n}\n\nexport async function deleteMobileRelayCredentialBundle(hostId: string): Promise<void> {\n  if (Platform.OS === 'web') {\n    return\n  }\n  await deletePairingKeychainItem(credentialKey(hostId))\n}\n\nfunction requireNativeSecretStore(): void {\n  if (Platform.OS === 'web') {\n    throw new Error('Orca Relay credentials require a native secret store')\n  }\n}\n","sourceCodeStart":90,"sourceCodeEnd":111,"githubUrl":"https://github.com/stablyai/orca/blob/1136503c6a231a16dce8f921f6fadb63d181e8db/mobile/src/transport/mobile-relay-credential-bundle.ts#L90-L111","documentation":"Thrown by `requireNativeSecretStore` in the relay credential bundle module when `Platform.OS === 'web'`. Orca Relay credentials live in the device's native SecureStore (Keychain/Keystore); the web target has no equivalent, so read/write of a bundle is refused rather than silently persisting to insecure browser storage.","triggerScenarios":"Calling `readMobileRelayCredentialBundle` or `writeMobileRelayCredentialBundle` while running on the web platform; importing the mobile relay module in a web test/storybook without a platform guard.","commonSituations":"A web build of the React Native app that links the mobile transport module; Storybook or Jest running under `Platform.OS = 'web'`; a shared import path that pulls credential code into the web bundle.","solutions":["Gate relay credential access on `Platform.OS !== 'web'` at the call site, or exclude this module from web builds.","On web, use a web-specific credential strategy (or none) rather than the native bundle functions.","In tests, mock `Platform.OS` to `'ios'`/`'android'` before exercising these functions."],"exampleFix":"// before\nimport { readMobileRelayCredentialBundle } from './mobile-relay-credential-bundle'\nconst bundle = await readMobileRelayCredentialBundle(hostId) // throws on web\n\n// after\nimport { Platform } from 'react-native'\nconst bundle = Platform.OS === 'web' ? null : await readMobileRelayCredentialBundle(hostId)","handlingStrategy":"type-guard","validationCode":"import { Platform } from 'react-native'\nif (Platform.OS === 'web') { /* use web credential strategy or skip */ return }","typeGuard":"function hasNativeSecretStore(): boolean { return Platform.OS !== 'web' }","tryCatchPattern":null,"preventionTips":["Gate all native keychain access on Platform.OS !== 'web'.","Exclude the credential-bundle module from web bundles via platform-specific entry points.","Mock Platform.OS in tests that exercise these functions."],"tags":["platform","web","storage","credentials"],"backgroundTag":null,"analyzedSha":"1136503c6a231a16dce8f921f6fadb63d181e8db","analyzedAt":"2026-08-12T23:15:58.167Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}