Skip to content

Desktop: Gemini API key entered in Settings is unreachable by geminiService (split IDB/filesystem persistence) #358

Description

@qnbs

Summary

On the Tauri desktop build, a Gemini API key entered via Settings → AI (components/ApiKeySection.tsx) is saved to the browser IndexedDB path (dbServiceservices/storage/idbKeyStore.ts), but services/geminiService.ts — the module that actually makes Gemini API calls — reads the key via storageService.getGeminiApiKey(), which on desktop resolves to the filesystem backend (services/fs/settingsFsStore.tsconfig/gemini_key.enc.json).

These are two entirely separate storage locations. A key saved through the Settings UI on desktop is therefore never found by geminiService.ts.

Evidence

  • components/ApiKeySection.tsx: imports dbService directly (services/dbService.ts), calls dbService.hasGeminiApiKey() / getGeminiApiKey() / saveGeminiApiKey() / clearGeminiApiKey().
  • services/geminiService.ts: imports storageService (services/storageService.ts), calls storageService.getGeminiApiKey() / clearGeminiApiKey().
  • services/storageService.ts: constructor sets this.backend = fileSystemService when isTauriRuntime(), so on desktop getGeminiApiKey() routes to services/fs/settingsFsStore.ts, never to IndexedDB.
  • Every other provider's key (OpenAI, OpenRouter, Claude, Grok, Ollama, etc.) is read/written exclusively through storageService/aiProviderService.ts on both platforms, so they don't have this split — Gemini is the exception because ApiKeySection.tsx predates the multi-provider storageService abstraction and was never migrated onto it.

Impact

On the desktop (Tauri) build, saving a Gemini key via Settings → AI silently appears to succeed (the UI reports "Active"), but Gemini generation calls will fail to find the key. This affects the default/flagship AI provider specifically.

Suggested fix

Route ApiKeySection.tsx through storageService instead of dbService directly, matching the pattern every other provider already uses. Note this isn't a pure find-and-replace: dbService.getGeminiApiKey() returns a 'DECRYPT_FAILED' sentinel string that ApiKeySection.tsx's decryptFailed UI state depends on; services/fs/settingsFsStore.ts#getApiKey() has no equivalent sentinel today (it returns null on any unreadable-file case). Reconciling that semantic gap — or reworking the UI to not depend on the sentinel — needs to be part of the fix, along with regression tests covering both the web (IDB) and desktop (fs) paths.

Found via

Surfaced by chatgpt-codex-connector's review of PR #352 (docs(security): correct false desktop encryption claims), while validating the desktop BYOK-API-key documentation. Filed as a separate tracked bug since it's a functional/availability issue distinct from that PR's docs-only scope — see the README.md "Encryption — which mechanism protects what" table's Desktop BYOK API key row for a pointer back here.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions