thedotmack/claude-mem · error · ServerClassifiedProviderError
auth_invalid
auth_invalid
Error message
Gemini API key not configured
What it means
The Gemini provider's constructor refuses to instantiate when `options.apiKey` is falsy. It throws a ServerClassifiedProviderError with kind 'auth_invalid' because requests without a key would fail Google's auth check anyway. This fails fast at construction time instead of at first request.
Solutions
- Set the Gemini API key env var (e.g. GEMINI_API_KEY) in the shell, .env file, or deployment secret store
- Check the exact option/env name used where the provider is constructed — the value is likely undefined, not absent by design
- Print the value's type (not its contents) to confirm it is a non-empty string before constructing the provider
- Verify .env files are actually loaded in the runtime (dotenv config called before provider construction)
Example fix
// before
const provider = new GeminiObservationProvider({ apiKey: process.env.GEMINI_KEY });
// after
const apiKey = process.env.GEMINI_API_KEY;
if (!apiKey) throw new Error('GEMINI_API_KEY is not set');
const provider = new GeminiObservationProvider({ apiKey }); Defensive patterns
Strategy: validation
Validate before calling
const apiKey = process.env.GEMINI_API_KEY;
if (typeof apiKey !== 'string' || apiKey.length === 0) {
throw new Error('GEMINI_API_KEY must be a non-empty string');
}
const provider = new GeminiObservationProvider({ apiKey }); Type guard
function hasApiKey(o: GeminiObservationProviderOptions): o is GeminiObservationProviderOptions & { apiKey: string } {
return typeof o.apiKey === 'string' && o.apiKey.length > 0;
} Try / catch
try {
provider = new GeminiObservationProvider({ apiKey });
} catch (e) {
if (e instanceof ServerClassifiedProviderError && e.kind === 'auth_invalid') {
throw new ConfigError('Gemini provider misconfigured: apiKey missing. Set GEMINI_API_KEY.');
}
throw e;
} Prevention
- Validate all required provider keys at application startup, before wiring providers
- Use a typed config loader that asserts presence of required env vars
- Never pass optional-chained values (config.x?.key) straight into provider constructors
- Document required env vars in .env.example and CI
When it happens
Trigger: Constructing `new GeminiObservationProvider({...})` with an options object whose `apiKey` property is undefined, null, or an empty string.
Common situations: Missing GEMINI_API_KEY / GOOGLE_API_KEY environment variable; reading the env var with the wrong name; a config loader returning undefined for an unset key; passing a variable that was never populated due to a typo in the key lookup.
Understand the failure class
Background: "API key is required" / "API key not found" / "No API key was set": the missing-api-key error family across 16 libraries — this error's family across 16 libraries.
Related errors
AI-assisted analysis of thedotmack/claude-mem@d8bc9755e7 (2026-09-17).
Data as JSON: /api/errors/26c9d40a80055c7d.
Report an issue: GitHub.
Appendix: source
Thrown at src/server/generation/providers/GeminiObservationProvider.ts:137
});
}
return classifyHttpProviderError({
...input,
providerLabel: 'Gemini',
});
}
export class GeminiObservationProvider implements ServerGenerationProvider {
readonly providerLabel = 'gemini' as const;
private readonly apiKey: string;
private readonly model: string;
private readonly maxOutputTokens: number;
private readonly fetchImpl: typeof fetch;
constructor(options: GeminiObservationProviderOptions) {
if (!options.apiKey) {
throw new ServerClassifiedProviderError('Gemini API key not configured', {
kind: 'auth_invalid',
cause: new Error('apiKey is required'),
});
}
this.apiKey = options.apiKey;
this.model = options.model ?? DEFAULT_MODEL;
this.maxOutputTokens = options.maxOutputTokens ?? 4096;
this.fetchImpl = options.fetchImpl ?? fetch;
}
async generate(
context: ServerGenerationContext,
signal?: AbortSignal,
): Promise<ServerGenerationResult> {
const { prompt, skippedAll } = buildServerGenerationPrompt(context);
if (skippedAll) {
return {
rawText: '<skip_summary reason="all_events_private" />',View on GitHub (pinned to d8bc9755e7)