{"record":{"id":"af66d354d03f0509","repo":"DayuanJiang/next-ai-draw-io","slug":"failed-to-encrypt-api-key-cannot-securely-store-c","errorCode":null,"errorMessage":"Failed to encrypt API key. Cannot securely store credentials.","messagePattern":"Failed to encrypt API key\\. Cannot securely store credentials\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"electron/main/config-manager.ts","lineNumber":55,"sourceCode":"    if (!isEncryptionAvailable()) {\n        if (!hasWarnedAboutPlaintext) {\n            console.warn(\n                \"⚠️ SECURITY WARNING: safeStorage not available. \" +\n                    \"API keys will be stored in PLAINTEXT. \" +\n                    \"On Linux, install gnome-keyring or similar for secure storage.\",\n            )\n            hasWarnedAboutPlaintext = true\n        }\n        return value\n    }\n\n    try {\n        const encrypted = safeStorage.encryptString(value)\n        return ENCRYPTED_PREFIX + encrypted.toString(\"base64\")\n    } catch (error) {\n        console.error(\"Encryption failed:\", error)\n        // Fail secure: don't store if encryption fails\n        throw new Error(\n            \"Failed to encrypt API key. Cannot securely store credentials.\",\n        )\n    }\n}\n\n/**\n * Decrypt a sensitive value using safeStorage\n * Returns the original value if it's not encrypted or decryption fails\n */\nfunction decryptValue(value: string): string {\n    if (!value || !value.startsWith(ENCRYPTED_PREFIX)) {\n        return value\n    }\n    if (!isEncryptionAvailable()) {\n        console.warn(\n            \"Cannot decrypt value: safeStorage encryption is not available\",\n        )\n        return value","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/DayuanJiang/next-ai-draw-io/blob/155ef4f7acd29c9d46fb6fc35c92e6e6955a6ce1/electron/main/config-manager.ts#L37-L73","documentation":"encryptValue uses Electron's safeStorage.encryptString; when the OS keychain/credential store is unavailable (Linux without libsecret, headless environments), encryption throws and the function fails secure rather than storing plaintext.","triggerScenarios":"Saving a config preset containing an API key on Linux without a secret service (gnome-keyring/KWallet) running, or in a sandboxed/headless Electron environment.","commonSituations":"Running the Electron app on a bare Linux WM without a keyring daemon, inside CI/containers, or after keyring service crashes.","solutions":["Install/start a secret service: sudo apt install gnome-keyring libsecret-tools, and ensure dbus + gnome-keyring-daemon are running","Set SAFE_STORAGE backend or use password-store backend where supported","Avoid storing API keys in presets on machines without a keyring; enter keys per-session","Check console.error output above the throw for the underlying keychain error"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import { safeStorage } from 'electron'\nconst canEncrypt = safeStorage.isEncryptionAvailable()","typeGuard":null,"tryCatchPattern":"try {\n  const enc = encryptValue(apiKey)\n} catch (e) {\n  if ((e as Error).message.includes('encrypt API key')) {\n    warnUserKeyringUnavailable(); storeWithoutKey()\n  }\n}","preventionTips":["Check safeStorage.isEncryptionAvailable() before offering 'save API key' in the UI","On Linux, ensure gnome-keyring/KWallet and dbus are running","Never fall back to storing plaintext silently — ask the user"],"tags":["electron","safestorage","encryption","keychain","linux"],"backgroundTag":"os-keychain-unavailable","analyzedSha":"155ef4f7acd29c9d46fb6fc35c92e6e6955a6ce1","analyzedAt":"2026-08-27T11:40:38.297Z","schemaVersion":2},"datasetVersion":"2026-08-27T13:17:12.746Z"}