thedotmack/claude-mem · error · ServerClientError
missing_api_key
missing_api_key
Error message
Server API key is not configured (CLAUDE_MEM_SERVER_API_KEY).
What it means
The ServerClient is the HTTP client hook subcommands use to reach the server runtime's /v1/* endpoints when server mode is selected. Before every request it checks that a non-empty API key was supplied at construction; the key normally originates from CLAUDE_MEM_SERVER_API_KEY. The guard ensures hooks never fire an unauthenticated request and, because missing_api_key is fallback-eligible (isFallbackEligible), lets the hook handler transparently fall back to the local worker path instead of hard-failing.
Source
Thrown at src/services/hooks/server-client.ts:349
projectId: input.projectId,
sourceType: input.sourceType,
eventType: input.eventType,
occurredAtEpoch: input.occurredAtEpoch,
...(input.serverSessionId !== undefined ? { serverSessionId: input.serverSessionId } : {}),
...(input.contentSessionId !== undefined ? { contentSessionId: input.contentSessionId } : {}),
...(input.memorySessionId !== undefined ? { memorySessionId: input.memorySessionId } : {}),
...(input.platformSource !== undefined ? { platformSource: normalizePlatformSourceField(input.platformSource) } : {}),
...(input.payload !== undefined ? { payload: input.payload } : {}),
};
}
private async request<T>(
method: 'GET' | 'POST',
path: string,
body?: unknown,
): Promise<T> {
if (!this.apiKey || !this.apiKey.trim()) {
throw new ServerClientError(
'missing_api_key',
'Server API key is not configured (CLAUDE_MEM_SERVER_API_KEY).',
);
}
const url = `${this.baseUrl}${path}`;
const init: RequestInit = {
method,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${this.apiKey}`,
},
};
if (body !== undefined) {
init.body = JSON.stringify(body);
}
let response: Response;View on GitHub (pinned to d768ba3643)
Solutions
- Export CLAUDE_MEM_SERVER_API_KEY with a valid server-issued key in the environment that runs claude-mem (and re-run the install so it is persisted to the settings file).
- Confirm the key is non-empty after trimming by inspecting the settings file the installer reads (look for an empty value or mismatched quotes around the key).
- If you did not intend server mode, re-run the installer and select the local/worker runtime so ServerClient is never constructed.
- Restart the worker after setting the key so the running process picks up the new env value.
Example fix
// before
const client = new ServerClient({ serverBaseUrl, apiKey: settings.CLAUDE_MEM_SERVER_API_KEY });
// settings.CLAUDE_MEM_SERVER_API_KEY === '' -> throws missing_api_key
// after
const apiKey = (settings.CLAUDE_MEM_SERVER_API_KEY ?? '').trim();
if (!apiKey) throw new Error('Set CLAUDE_MEM_SERVER_API_KEY before enabling server mode');
const client = new ServerClient({ serverBaseUrl, apiKey }); Defensive patterns
Strategy: validation
Validate before calling
import { isServerClientError, ServerClient } from './server-client.js';
function makeClient(serverBaseUrl: string, apiKey?: string): ServerClient {
const key = (apiKey ?? '').trim();
if (!key) {
throw new Error('CLAUDE_MEM_SERVER_API_KEY is missing; cannot use server mode');
}
return new ServerClient({ serverBaseUrl, apiKey: key });
} Type guard
import { ServerClientError } from './server-client.js';
function isMissingApiKey(e: unknown): boolean {
return e instanceof ServerClientError && e.kind === 'missing_api_key';
} Try / catch
try {
await client.recordEvent(input);
} catch (e) {
if (e instanceof ServerClientError && e.isFallbackEligible()) {
await worker.recordEvent(input); // missing_api_key is fallback-eligible
return;
}
throw e;
} Prevention
- Centralize ServerClient construction in one factory that validates the API key and fails loudly at startup.
- Persist CLAUDE_MEM_SERVER_API_KEY through the installer so the worker reads it on every launch.
- Log a clear message at worker boot when server mode is on but the key is empty.
When it happens
Trigger: Any ServerClient method (startSession, recordEvent, endSession, addObservation, searchObservations, contextObservations, getJobStatus) is invoked while this.apiKey is undefined, empty string, or whitespace-only after trim(). The check runs at the top of the private request<T>() method, so every endpoint hits it.
Common situations: CLAUDE_MEM_SERVER_API_KEY env var was never exported in the shell that launched the worker/hooks; the installer wrote an empty quoted value into the settings file; server mode was selected during install but no API key was provisioned yet; CI/container environment forgot to inject the secret; the key was loaded from the wrong settings file path.
Related errors
- timeout|transport
- http_error
- Invalid CLAUDE_MEM_WORKER_PORT in settings.json: missing
- Invalid CLAUDE_MEM_WORKER_PORT in settings.json: ${rawPort}
- GitHub CLI is not authenticated. Run "gh auth login". ${auth
AI-assisted analysis of thedotmack/claude-mem@d768ba3643 (2026-08-12).
Data as JSON: /api/errors/889b643fca1ca096.
Report an issue: GitHub.