{"record":{"id":"7d8b5351f9f1b635","repo":"different-ai/openwork","slug":"operating-system-secure-storage-is-unavailable-for","errorCode":null,"errorMessage":"Operating-system secure storage is unavailable for OpenWork-managed OAuth.","messagePattern":"Operating-system secure storage is unavailable for OpenWork-managed OAuth\\.","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"apps/desktop/electron/secure-vault-key.mjs","lineNumber":74,"sourceCode":" *\n * @param {{\n *   filePath: string;\n *   loadSafeStorage: () => import(\"electron\").SafeStorage;\n *   platform?: NodeJS.Platform;\n * }} options\n */\nexport function createDesktopVaultKeyProvider({\n  filePath,\n  loadSafeStorage,\n  platform = process.platform,\n}) {\n  /** @type {Promise<Buffer> | null} */\n  let pending = null;\n\n  async function loadKey() {\n    const safeStorage = loadSafeStorage();\n    if (!safeStorage || !(await safeStorage.isAsyncEncryptionAvailable())) {\n      throw new Error(\"Operating-system secure storage is unavailable for OpenWork-managed OAuth.\");\n    }\n    if (platform === \"linux\" && safeStorage.getSelectedStorageBackend() === \"basic_text\") {\n      throw new Error(\"A secure Linux password store is required for OpenWork-managed OAuth.\");\n    }\n\n    /** @type {Buffer | undefined} */\n    let encrypted;\n    try {\n      encrypted = await readFile(filePath);\n    } catch (error) {\n      if (error?.code !== \"ENOENT\") throw error;\n    }\n\n    if (encrypted) {\n      /** @type {Awaited<ReturnType<typeof safeStorage.decryptStringAsync>> | undefined} */\n      let decrypted;\n      /** @type {Buffer | undefined} */\n      let key;","sourceCodeStart":56,"sourceCodeEnd":92,"githubUrl":"https://github.com/different-ai/openwork/blob/2b7df46e8ae1517d64c896c7793d2d52ec845669/apps/desktop/electron/secure-vault-key.mjs#L56-L92","documentation":"Thrown by `loadKey` when Electron's `safeStorage` is unavailable or reports that asynchronous OS-level encryption is not available. OpenWork-managed OAuth requires the operating system's credential store (Keychain, DPAPI, kwallet, etc.) to encrypt the vault key at rest; without it the module refuses to proceed rather than storing plaintext.","triggerScenarios":"Running outside a fully initialized Electron app (safeStorage module missing), a platform/browser build without OS credential-store integration, or `isAsyncEncryptionAvailable()` returning false due to a missing keyring service.","commonSituations":"Headless/CI Linux environments with no keyring daemon; Electron run in environments where the OS credential service is disabled; running the module in plain Node instead of Electron main process.","solutions":["Run the app as a normal Electron main-process environment with an OS keyring available","On Linux, install/enable a keyring service (gnome-keyring, KWallet) and ensure a desktop keyring session is active","For CI/headless, use a virtual keyring (e.g. gnome-keyring with dbus) or document the limitation"],"exampleFix":"// before\n// loadKey() throws: no safeStorage in bare Node script\n// after\n// only invoke the vault from Electron main after app is ready\napp.whenReady().then(() => {\n  const key = await getKeyProvider()(); // safeStorage available here\n});","handlingStrategy":"try-catch","validationCode":"async function secureStorageReady(safeStorage) {\n  return Boolean(safeStorage) && (await safeStorage.isEncryptionAvailable?.());\n}","typeGuard":null,"tryCatchPattern":"try {\n  const key = await getKey();\n} catch (e) {\n  if (e.message.startsWith('Operating-system secure storage is unavailable')) {\n    showSetupGuide('Enable OS keyring / run inside Electron');\n  } else throw e;\n}","preventionTips":["Only use the vault from the Electron main process after app ready","Detect keyring availability early and surface setup instructions","Avoid running the app in environments without a credential store","Test on a fresh machine profile to catch missing-keyring cases"],"tags":["electron","safe-storage","keyring","oauth"],"backgroundTag":"os-keyring-unavailable","analyzedSha":"2b7df46e8ae1517d64c896c7793d2d52ec845669","analyzedAt":"2026-09-01T07:59:23.713Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}