thedotmack/claude-mem · error
Forbidden
Forbidden
Error message
Invalid API key or insufficient scope
What it means
403 from the SQLite auth middleware: a key was presented but verifyServerApiKey returned null, meaning the key does not exist, is revoked/expired, or lacks one of the route's requiredScopes (e.g. memories:write on the compat summarize route). Note the distinction from 401 — 401 means no key, 403 means the key failed verification or scope.
Source
Thrown at src/server/middleware/auth.ts:80
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,
apiKeyId: verified.record.id,
mode: 'api-key',
};
next();
};
}
View on GitHub (pinned to e2d1df569a)
Solutions
- Re-copy the full key with no trailing whitespace/newline and retry.
- Confirm the key exists and is active in the server's database (keys table / key management endpoint).
- Check the route's requiredScopes and mint a key that includes them (e.g. memories:write for summarize).
- If keys were rotated, update the client's stored credential.
Defensive patterns
Strategy: validation
Validate before calling
// Verify key validity + scopes before real work (cheapest probe: an authenticated read)
const probe = await fetch(`${base}/v1/keys`, { headers: { 'X-Api-Key': key } });
if (probe.status === 403) {
throw new Error('Key invalid or missing required scope — remint before continuing');
} Type guard
function isInvalidKeyResponse(res: Response): boolean {
return res.status === 403;
}
interface ForbiddenBody { error: string; message: string }
function isInvalidKeyBody(body: unknown): body is ForbiddenBody {
return typeof body === 'object' && body !== null &&
(body as ForbiddenBody).error === 'Forbidden' &&
(body as ForbiddenBody).message === 'Invalid API key or insufficient scope';
} Prevention
- Never hardcode scopes per call site — derive them from a shared per-endpoint map.
- Rotate keys atomically: mint new, switch clients, then revoke old.
- Trim whitespace when loading keys from env/files.
When it happens
Trigger: Request with a mistyped or truncated key; a key deleted or rotated server-side while clients still hold the old value; a read-only key (no memories:write) hitting POST /api/sessions/summarize whose writeAuth requires memories:write; key exists in a different database/environment than the one serving the request.
Common situations: Key rotation deployed to server but clients cached the old key; copy-paste lost characters or gained whitespace/newline; dev pointed at prod with a dev-database key; scope set at mint time omitted the write scope the endpoint needs.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of thedotmack/claude-mem@e2d1df569a (2026-08-20).
Data as JSON: /api/errors/0e6c5b38cb5fb5b0.
Report an issue: GitHub.