{"record":{"id":"04497990c63e11a1","repo":"decolua/9router","slug":"invalid-api-key-044979","errorCode":null,"errorMessage":"Invalid API key","messagePattern":"Invalid API key","errorType":"validation","errorClass":null,"httpStatus":401,"severity":"error","filePath":"src/sse/handlers/embeddings.js","lineNumber":63,"sourceCode":"\n  // Log API key (masked)\n  const apiKey = extractApiKey(request);\n  if (apiKey) {\n    log.debug(\"AUTH\", `API Key: ${log.maskKey(apiKey)}`);\n  } else {\n    log.debug(\"AUTH\", \"No API key provided (local mode)\");\n  }\n\n  // Enforce API key if enabled in settings\n  const settings = await getSettings();\n  if (settings.requireApiKey) {\n    if (!apiKey) {\n      log.warn(\"AUTH\", \"Missing API key (requireApiKey=true)\");\n      return errorResponse(HTTP_STATUS.UNAUTHORIZED, \"Missing API key\");\n    }\n    const valid = await isValidApiKey(apiKey);\n    if (!valid) {\n      log.warn(\"AUTH\", \"Invalid API key (requireApiKey=true)\");\n      return errorResponse(HTTP_STATUS.UNAUTHORIZED, \"Invalid API key\");\n    }\n  }\n\n  if (!modelStr) {\n    log.warn(\"EMBEDDINGS\", \"Missing model\");\n    return errorResponse(HTTP_STATUS.BAD_REQUEST, \"Missing model\");\n  }\n\n  if (!body.input) {\n    log.warn(\"EMBEDDINGS\", \"Missing input\");\n    return errorResponse(HTTP_STATUS.BAD_REQUEST, \"Missing required field: input\");\n  }\n\n  const modelInfo = await getModelInfo(modelStr);\n  if (!modelInfo.provider) {\n    log.warn(\"EMBEDDINGS\", \"Invalid model format\", { model: modelStr });\n    return errorResponse(HTTP_STATUS.BAD_REQUEST, \"Invalid model format\");","sourceCodeStart":45,"sourceCodeEnd":81,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/sse/handlers/embeddings.js#L45-L81","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nconst res = await fetch('http://localhost:20128/v1/embeddings', { method: 'POST', body: JSON.stringify(payload) });\n// after\nconst res = await fetch('http://localhost:20128/v1/embeddings', { method: 'POST', headers: { Authorization: `Bearer ${ROUTER_API_KEY}` }, body: JSON.stringify(payload) });","handlingStrategy":"validation","validationCode":"const key = process.env.ROUTER_API_KEY;\nif (!key || key.length < 8) throw new Error('ROUTER_API_KEY not configured');\n// and confirm it matches the dashboard settings key before each deploy","typeGuard":"function hasApiKey(headers) {\n  const h = headers.get('authorization') ?? '';\n  return h.startsWith('Bearer ') && h.slice(7).trim().length > 0;\n}","tryCatchPattern":"if (res.status === 401 && (await res.text()).includes('Invalid API key')) {\n  console.error('Gateway rejected the API key — re-check ROUTER_API_KEY against dashboard settings');\n}","preventionTips":["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"],"tags":["auth","api-key","http-401"],"backgroundTag":"invalid-api-key","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}