thedotmack/claude-mem · error
Unauthorized
Unauthorized
Error message
Missing API key (Authorization: Bearer <key> or X-Api-Key: <key>)
What it means
401 from the SQLite auth middleware when the request carries no API key at all. The middleware extracts the key from Authorization: Bearer <key> or X-Api-Key: <key>; when local-dev mode is disabled and rawKey is empty, it rejects immediately with this message documenting both accepted header forms.
Source
Thrown at src/server/middleware/auth.ts:71
&& isLocalhost(req)
&& hasLoopbackHostHeader(req)
&& !hasForwardedClientHeaders(req)
) {
req.authContext = {
userId: null,
organizationId: null,
teamId: null,
projectId: null,
scopes: ['local-dev'],
apiKeyId: null,
mode: 'local-dev',
};
next();
return;
}
if (!rawKey) {
res.status(401).json({
error: 'Unauthorized',
message: 'Missing API key (Authorization: Bearer <key> or X-Api-Key: <key>)',
});
return;
}
const verified = verifyServerApiKey(getDatabase(), rawKey, options.requiredScopes ?? []);
if (!verified) {
res.status(403).json({ error: 'Forbidden', message: 'Invalid API key or insufficient scope' });
return;
}
req.authContext = {
userId: null,
organizationId: null,
teamId: verified.teamId,
projectId: verified.projectId,
scopes: verified.scopes,View on GitHub (pinned to e2d1df569a)
Solutions
- Send the key in one of the two accepted headers: Authorization: Bearer <key> or X-Api-Key: <key>.
- Check the environment variable that carries the key is actually set in the client's environment (print its presence, never its value).
- If you intended to run without keys, enable the server's local-dev mode — but never in production.
- Verify the header name spelling and that no proxy strips Authorization on its way to the server.
Example fix
# before
curl -X POST https://host/api/sessions/summarize -d '{}'
// 401 Missing API key
# after
curl -X POST https://host/api/sessions/summarize \
-H 'Authorization: Bearer sk-...' \
-H 'Content-Type: application/json' \
-d '{"contentSessionId":"..."}' Defensive patterns
Strategy: validation
Validate before calling
function buildHeaders(key: string | undefined): Record<string, string> {
if (!key) throw new Error('API key is not configured (set API_KEY)');
return { 'X-Api-Key': key, 'Content-Type': 'application/json' };
} Type guard
interface UnauthorizedBody { error: string; message: string }
function isMissingApiKey(body: unknown): body is UnauthorizedBody {
return typeof body === 'object' && body !== null &&
(body as UnauthorizedBody).error === 'Unauthorized' &&
(body as UnauthorizedBody).message?.startsWith('Missing API key');
} Prevention
- Fail fast at startup when the key env var is unset rather than on first request.
- Centralize auth header construction in one client wrapper.
- Assert the key is non-empty and not the literal 'undefined'.
When it happens
Trigger: Any request to a protected route (e.g. POST /api/sessions/summarize) with neither Authorization nor X-Api-Key header; header name typo like X-API-Key with wrong casing in a raw client (case-insensitive in HTTP, but misspelled names fail); env var holding the key is unset so the client sends 'Bearer undefined'.
Common situations: Forgot to set API_KEY in .env so the client sends an empty/undefined token; curl invocation missing -H; switching a script from local-dev (where no key is needed) to a deployed server where local-dev is off.
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@e2d1df569a (2026-08-20).
Data as JSON: /api/errors/3fb1107f36ca7c0b.
Report an issue: GitHub.