different-ai/openwork · error

A secure Linux password store is required for OpenWork-manag

Error message

A secure Linux password store is required for OpenWork-managed OAuth.

What it means

Thrown by `loadKey` on Linux when safeStorage's selected storage backend is `basic_text`, meaning Electron is falling back to plain obfuscated text on disk instead of a real OS password store. OpenWork rejects this because the OAuth credential key would not be genuinely encrypted, so it demands a secure keyring backend.

Source

Thrown at apps/desktop/electron/secure-vault-key.mjs:77

 *   loadSafeStorage: () => import("electron").SafeStorage;
 *   platform?: NodeJS.Platform;
 * }} options
 */
export function createDesktopVaultKeyProvider({
  filePath,
  loadSafeStorage,
  platform = process.platform,
}) {
  /** @type {Promise<Buffer> | null} */
  let pending = null;

  async function loadKey() {
    const safeStorage = loadSafeStorage();
    if (!safeStorage || !(await safeStorage.isAsyncEncryptionAvailable())) {
      throw new Error("Operating-system secure storage is unavailable for OpenWork-managed OAuth.");
    }
    if (platform === "linux" && safeStorage.getSelectedStorageBackend() === "basic_text") {
      throw new Error("A secure Linux password store is required for OpenWork-managed OAuth.");
    }

    /** @type {Buffer | undefined} */
    let encrypted;
    try {
      encrypted = await readFile(filePath);
    } catch (error) {
      if (error?.code !== "ENOENT") throw error;
    }

    if (encrypted) {
      /** @type {Awaited<ReturnType<typeof safeStorage.decryptStringAsync>> | undefined} */
      let decrypted;
      /** @type {Buffer | undefined} */
      let key;
      try {
        decrypted = await safeStorage.decryptStringAsync(encrypted);
        key = decodeKey(decrypted.result);

View on GitHub (pinned to 2b7df46e8a)

Solutions

  1. Install and unlock gnome-keyring (or KWallet) and ensure it runs in your desktop session
  2. Launch the app with a proper dbus session so Electron can talk to the keyring
  3. On headless/CI, start a virtual keyring (gnome-keyring-daemon) before launching
  4. Confirm via safeStorage.getSelectedStorageBackend() that the backend is no longer basic_text

Example fix

// before
// electron .  -> backend is basic_text
// after
# start a keyring and dbus session first
eval $(dbus-launch)
gnome-keyring-daemon --start --components=secrets
electron .
Defensive patterns

Strategy: validation

Validate before calling

function linuxBackendIsSecure(safeStorage, platform) {
  return platform !== 'linux' || safeStorage.getSelectedStorageBackend() !== 'basic_text';
}

Try / catch

try {
  const key = await getKey();
} catch (e) {
  if (e.message.startsWith('A secure Linux password store is required')) {
    showLinuxKeyringInstructions();
  } else throw e;
}

Prevention

When it happens

Trigger: On Linux, `safeStorage.getSelectedStorageBackend()` returns `basic_text` — typically because gnome-keyring/KWallet is absent or no keyring is unlocked in the session (headless, SSH, minimal window managers).

Common situations: Running the app in a minimal Linux desktop or WSL without gnome-keyring; headless/CI sessions; Docker containers; distros without a default keyring daemon; session started before keyring service.

Related errors


AI-assisted analysis of different-ai/openwork@2b7df46e8a (2026-09-01). Data as JSON: /api/errors/486497ba463ada50. Report an issue: GitHub.