diff --git a/NexusAI/packages/core/src/db/providers-store.ts b/NexusAI/packages/core/src/db/providers-store.ts index b81db80..200ee39 100644 --- a/NexusAI/packages/core/src/db/providers-store.ts +++ b/NexusAI/packages/core/src/db/providers-store.ts @@ -133,12 +133,17 @@ export class ProvidersStore { this.db.prepare('DELETE FROM providers WHERE name = ?').run(name); } - /** Return the decrypted API key for a provider, or undefined. */ + /** + * Return the decrypted API key for a provider, or undefined. + * Returns undefined (instead of throwing) when no master key is configured, + * so callers can gracefully fall back to env keys. + */ getApiKey(name: string): string | undefined { const row = this.db.prepare('SELECT api_key_enc FROM providers WHERE name = ?').get(name) as | { api_key_enc: string | null } | undefined; if (!row?.api_key_enc) return undefined; + if (!this.cipher.enabled) return undefined; return this.cipher.decrypt(row.api_key_enc); } diff --git a/NexusAI/packages/core/src/security/resolver.ts b/NexusAI/packages/core/src/security/resolver.ts index fff82bb..5eec369 100644 --- a/NexusAI/packages/core/src/security/resolver.ts +++ b/NexusAI/packages/core/src/security/resolver.ts @@ -45,7 +45,18 @@ export class KeyResolver { resolve(providerName: string, defaultBaseUrl: string): ResolvedProvider { const dbRow = this.store?.get(providerName); const envKey = this.envKeyFor(providerName); - const dbKey = this.store?.getApiKey(providerName); + // DB key may be unreadable (no master key / rotated key). Degrade gracefully: + // fall back to env instead of crashing startup. + let dbKey: string | undefined; + try { + dbKey = this.store?.getApiKey(providerName); + } catch (err) { + log.warn( + `could not read stored key for "${providerName}" (falling back to env)`, + err instanceof Error ? err.message : String(err) + ); + dbKey = undefined; + } const apiKey = envKey ?? dbKey; const keySource: ResolvedProvider['keySource'] = envKey ? 'env' : dbKey ? 'db' : 'none';