decolua/9router · error
Invalid API key
Error message
Invalid API key
What it means
HTTP 401 returned by handleEmbeddings when the gateway's requireApiKey setting is enabled and the Authorization/API-key header value fails isValidApiKey. The router validates the caller's local gateway key (not an upstream provider key) before routing the embeddings request. It exists to reject unauthorized callers once API-key enforcement is turned on.
Source
Thrown at src/sse/handlers/embeddings.js:63
// Log API key (masked)
const apiKey = extractApiKey(request);
if (apiKey) {
log.debug("AUTH", `API Key: ${log.maskKey(apiKey)}`);
} else {
log.debug("AUTH", "No API key provided (local mode)");
}
// Enforce API key if enabled in settings
const settings = await getSettings();
if (settings.requireApiKey) {
if (!apiKey) {
log.warn("AUTH", "Missing API key (requireApiKey=true)");
return errorResponse(HTTP_STATUS.UNAUTHORIZED, "Missing API key");
}
const valid = await isValidApiKey(apiKey);
if (!valid) {
log.warn("AUTH", "Invalid API key (requireApiKey=true)");
return errorResponse(HTTP_STATUS.UNAUTHORIZED, "Invalid API key");
}
}
if (!modelStr) {
log.warn("EMBEDDINGS", "Missing model");
return errorResponse(HTTP_STATUS.BAD_REQUEST, "Missing model");
}
if (!body.input) {
log.warn("EMBEDDINGS", "Missing input");
return errorResponse(HTTP_STATUS.BAD_REQUEST, "Missing required field: input");
}
const modelInfo = await getModelInfo(modelStr);
if (!modelInfo.provider) {
log.warn("EMBEDDINGS", "Invalid model format", { model: modelStr });
return errorResponse(HTTP_STATUS.BAD_REQUEST, "Invalid model format");View on GitHub (pinned to 90b52e06ff)
Solutions
- Check the API key configured in the dashboard settings and copy it exactly into the client's Authorization header
- Ensure the client targets the correct router instance/environment where that key is set
- If local-only use, disable requireApiKey in settings (not recommended for exposed hosts)
- Restart/redeploy the router if the key was just changed and caching is suspected
Example fix
// before
const res = await fetch('http://localhost:20128/v1/embeddings', { method: 'POST', body: JSON.stringify(payload) });
// after
const res = await fetch('http://localhost:20128/v1/embeddings', { method: 'POST', headers: { Authorization: `Bearer ${ROUTER_API_KEY}` }, body: JSON.stringify(payload) }); Defensive patterns
Strategy: validation
Validate before calling
const key = process.env.ROUTER_API_KEY;
if (!key || key.length < 8) throw new Error('ROUTER_API_KEY not configured');
// and confirm it matches the dashboard settings key before each deploy Type guard
function hasApiKey(headers) {
const h = headers.get('authorization') ?? '';
return h.startsWith('Bearer ') && h.slice(7).trim().length > 0;
} Try / catch
if (res.status === 401 && (await res.text()).includes('Invalid API key')) {
console.error('Gateway rejected the API key — re-check ROUTER_API_KEY against dashboard settings');
} Prevention
- Store the gateway key in one env var and reference it everywhere
- Re-copy the key after any dashboard settings change
- Never hardcode keys in scripts; use env/config
- Distinguish the gateway key from upstream provider keys in naming
When it happens
Trigger: POST to the embeddings endpoint with an Authorization header (or api key header) whose value does not match the gateway's configured API key, while requireApiKey=true in dashboard settings.
Common situations: User enabled requireApiKey in the dashboard but the client SDK still sends a stale or placeholder key; key was rotated in the dashboard; the key was sent to a different env (dev vs prod gateway); using an upstream provider key instead of the router's own key.
Understand the failure class
- Authentication and authorization failures — expired tokens, bad credentials, and missing scopes.
Related errors
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/04497990c63e11a1.
Report an issue: GitHub.