decolua/9router · error
Missing API key
Error message
Missing API key
What it means
requireApiKey is enabled in gateway settings but the embeddings request carried no API key. extractApiKey(request) returned nothing, so handleEmbeddings returns 401 'Missing API key' — identical policy to the chat handler.
Source
Thrown at src/sse/handlers/embeddings.js:58
const url = new URL(request.url);
const modelStr = body.model;
log.request("POST", `${url.pathname} | ${modelStr}`);
// 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");
}View on GitHub (pinned to 90b52e06ff)
Solutions
- Send Authorization: Bearer <9router-api-key> (or x-api-key) with embeddings requests.
- Set the apiKey option in your embedding client/driver, not just baseURL.
- Disable requireApiKey in dashboard settings if this is a trusted local-only deployment.
- Verify no intermediary strips auth headers before the gateway.
Example fix
// before
const embedder = new OpenAIEmbeddings({ baseURL: 'http://localhost:20128/v1' });
// after
const embedder = new OpenAIEmbeddings({
baseURL: 'http://localhost:20128/v1',
apiKey: process.env.NINE_ROUTER_API_KEY
}); Defensive patterns
Strategy: validation
Validate before calling
const apiKey = process.env.NINE_ROUTER_API_KEY;
if (!apiKey) throw new Error('embeddings client requires an API key (requireApiKey is on)');
opts.headers = { ...opts.headers, Authorization: `Bearer ${apiKey}` }; Type guard
function requestHasKey(opts) {
const h = opts.headers || {};
return Boolean(h['x-api-key']) || /^Bearer\s+\S+/.test(h['Authorization'] || h['authorization'] || '');
} Try / catch
const res = await fetch(embedUrl, opts);
if (res.status === 401 && (await res.text()).includes('Missing API key')) {
throw new Error('Add Authorization: Bearer <9router key> to embeddings requests');
} Prevention
- Set apiKey in embedding clients (LangChain/OpenAI SDK), not just baseURL.
- Centralize auth-header construction in one request wrapper for all endpoints.
- Verify requireApiKey setting whenever cloning environments.
- Integration-test one embeddings call per deployment to catch auth regressions.
When it happens
Trigger: POST /v1/embeddings with settings.requireApiKey=true and no Authorization/x-api-key header on the request.
Common situations: Embedding clients (custom scripts, LangChain embeddings wrappers) configured with baseURL only and no key because embeddings calls were previously unauthenticated; enforcement toggled on after deployment; a reverse proxy stripping the Authorization header.
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
- Missing API key
- Invalid API key
- Missing API key
- qoder PAT exchange failed: ${res.status} ${text.slice(0, 200
- GitHub API error: ${error}
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/b023db9bbaa27b6f.
Report an issue: GitHub.