NousResearch/hermes-agent · error

Failed to encrypt the remote gateway token for secure storag

Error message

Failed to encrypt the remote gateway token for secure storage${detail}. Set HERMES_DESKTOP_REMOTE_URL and HERMES_DESKTOP_REMOTE_TOKEN in your environment as a fallback.

What it means

Thrown when safeStorage IS available (the availability check passed) but the actual encryptString(raw) call throws. This distinguishes it from the 'no keyring' error: here the OS keyring exists, yet the encryption operation itself failed — often a locked keyring, a D-Bus hiccup, or a backend quirk. The original error message is appended as detail.

Source

Thrown at apps/desktop/electron/hardening.ts:207

      return { encoding: 'plain', value: raw }
    }

    throw new Error(
      'Secure token storage is unavailable (no OS keyring service was found), so Hermes Desktop cannot save remote gateway tokens. ' +
        'Either enable an OS keyring (e.g. GNOME Keyring or KWallet providing org.freedesktop.secrets) and try again, ' +
        'confirm the plain-text storage option when prompted in Settings → Gateway, ' +
        'or set HERMES_DESKTOP_REMOTE_URL and HERMES_DESKTOP_REMOTE_TOKEN in your environment.'
    )
  }

  try {
    return {
      encoding: SAFE_STORAGE_ENCODING,
      value: safeStorageApi.encryptString(raw).toString('base64')
    }
  } catch (error) {
    const detail = error instanceof Error && error.message ? ` (${error.message})` : ''
    throw new Error(
      `Failed to encrypt the remote gateway token for secure storage${detail}. ` +
        'Set HERMES_DESKTOP_REMOTE_URL and HERMES_DESKTOP_REMOTE_TOKEN in your environment as a fallback.'
    )
  }
}

// Keyring-less Linux (e.g. Hyprland/Sway with no GNOME Keyring or KWallet):
// `--password-store=basic` selects Electron's built-in "basic" backend, but
// Electron only counts it as available once setUsePlainTextEncryption(true) is
// called. The caller runs this on whenReady, before createWindow() and anything
// that could touch safeStorage, so the switch takes effect for the whole run.
//
// Semantics are deliberately narrow: only linux, only the exact 'basic' switch
// value (never 'gnome-libsecret', 'kwallet', '', etc.), and only when the
// method exists (older/mocked safeStorage may lack it) and does not throw.
// Anything else is a no-op. Returns true only when it actually flipped the flag,
// so the caller (and tests) can distinguish "enabled" from "left untouched".
// Never throws: a failure here is non-fatal — encryption simply stays

View on GitHub (pinned to c896c09c42)

Solutions

  1. Unlock the keyring (open the keyring prompt / `gnome-keyring-daemon --unlock`) and retry the save.
  2. Restart the keyring service or the D-Bus session if it crashed.
  3. As a workaround set HERMES_DESKTOP_REMOTE_URL and HERMES_DESKTOP_REMOTE_TOKEN in the environment, as the message suggests.
  4. Read the appended detail in parentheses — it carries the underlying error text for diagnosis.
Defensive patterns

Strategy: retry

Try / catch

try {
  await saveRemoteToken(token)
} catch (e) {
  if (/Failed to encrypt/.test(e.message)) {
    await notifyUser('Unlock your OS keyring and retry, or use env-var credentials.')
  } else throw e
}

Prevention

When it happens

Trigger: Keyring service present but locked at the moment of the call; keyring daemon crashed mid-call; KWallet timing out; any exception from safeStorageApi.encryptString(raw).

Common situations: Saving a gateway token right after login before the keyring unlocks; flaky D-Bus sessions; unusual keyring backends (keepassxc proxy) that partially implement the API.

Related errors


AI-assisted analysis of NousResearch/hermes-agent@c896c09c42 (2026-08-14). Data as JSON: /api/errors/b66c9547738db652. Report an issue: GitHub.