{"record":{"id":"f9dfcd1268a30525","repo":"decolua/9router","slug":"invalid-api-key","errorCode":null,"errorMessage":"Invalid API key","messagePattern":"Invalid API key","errorType":"validation","errorClass":null,"httpStatus":401,"severity":"error","filePath":"src/sse/handlers/chat.js","lineNumber":73,"sourceCode":"  const authHeader = request.headers.get(\"Authorization\");\n  const apiKey = extractApiKey(request);\n  if (authHeader && apiKey) {\n    const masked = log.maskKey(apiKey);\n    log.debug(\"AUTH\", `API Key: ${masked}`);\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(\"CHAT\", \"Missing model\");\n    return errorResponse(HTTP_STATUS.BAD_REQUEST, \"Missing model\");\n  }\n\n  // Bypass naming/warmup requests before combo rotation to avoid wasting rotation slots\n  const userAgent = request?.headers?.get(\"user-agent\") || \"\";\n  const bypassResponse = handleBypassRequest(body, modelStr, userAgent, !!settings.ccFilterNaming);\n  if (bypassResponse) return bypassResponse.response || bypassResponse;\n\n  const requiredCapabilities = detectRequiredCapabilities(body);\n\n  // Check if model is a combo (has multiple models with fallback)\n  const comboModels = await getComboModels(modelStr);","sourceCodeStart":55,"sourceCodeEnd":91,"githubUrl":"https://github.com/decolua/9router/blob/90b52e06ffd666b7929554211474d01588f6b1f8/src/sse/handlers/chat.js#L55-L91","documentation":"API-key enforcement is on (requireApiKey=true), a key was supplied, but isValidApiKey rejected it. The handler returns 401 'Invalid API key'. The gateway validates the presented key against keys stored in its settings/database.","triggerScenarios":"POST to /v1/chat/completions with Authorization: Bearer <key> where <key> does not match any key registered in the 9Router dashboard while settings.requireApiKey=true.","commonSituations":"Typo or stale key in the client env (pointing at an upstream provider key like OPENAI_API_KEY instead of a 9Router key); key rotated/regenerated in the dashboard but old value cached in .env; extra whitespace or quotes in the env var; multiple environments sharing one config.","solutions":["Open the 9Router dashboard and copy the exact current API key, then update the client env/config.","Check for stray whitespace/quotes in the env var: API_KEY=\"abc\" in .env often embeds literal quotes.","Make sure you are using a 9Router-issued key, not an upstream provider key.","If the key was rotated, restart the client so it reloads the new value."],"exampleFix":"// before (.env)\nOPENAI_API_KEY=\"sk-abc123\"   # literal quotes end up in the value\n\n// after (.env)\nAPI_KEY=sk-abc123            # correct 9Router key, no quotes/whitespace","handlingStrategy":"validation","validationCode":"const apiKey = (process.env.NINE_ROUTER_API_KEY || '').trim();\nif (!apiKey) throw new Error('missing 9router api key');\nif (/^[\"'].*[\"']$/.test(process.env.NINE_ROUTER_API_KEY)) throw new Error('api key env var contains literal quotes');","typeGuard":"function looksLikeGatewayKey(key) {\n  return typeof key === 'string' && key.trim().length > 0 && !/[\"']/.test(key);\n}","tryCatchPattern":"const res = await fetch(url, { headers });\nif (res.status === 401 && (await res.text()).includes('Invalid API key')) {\n  throw new Error('API key rejected by 9Router — re-copy the key from the dashboard');\n}","preventionTips":["Copy keys from the dashboard verbatim; trim whitespace.","Never put quotes inside .env values.","Rotate keys in the client config at the same time as the dashboard.","Use a 9Router-issued key, not an upstream provider key."],"tags":["auth","http","unauthorized","api-key"],"backgroundTag":"invalid-api-key","analyzedSha":"90b52e06ffd666b7929554211474d01588f6b1f8","analyzedAt":"2026-08-30T21:05:45.952Z","schemaVersion":2},"datasetVersion":"2026-08-30T23:17:21.991Z"}