decolua/9router · error

Missing API key

Error message

Missing API key

What it means

API-key enforcement is enabled in the gateway settings (requireApiKey=true) but no API key was found on the request. extractApiKey(request) looks at the Authorization header (Bearer token) and possibly x-api-key; when it returns nothing and enforcement is on, the handler returns 401 with 'Missing API key'.

Source

Thrown at src/sse/handlers/chat.js:68

  const modelStr = body.model;

  // Request summary is emitted as the unified "▶" line in chatCore (has fmt/thinking/account)

  // Log API key (masked)
  const authHeader = request.headers.get("Authorization");
  const apiKey = extractApiKey(request);
  if (authHeader && apiKey) {
    const masked = log.maskKey(apiKey);
    log.debug("AUTH", `API Key: ${masked}`);
  } 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("CHAT", "Missing model");
    return errorResponse(HTTP_STATUS.BAD_REQUEST, "Missing model");
  }

  // Bypass naming/warmup requests before combo rotation to avoid wasting rotation slots
  const userAgent = request?.headers?.get("user-agent") || "";
  const bypassResponse = handleBypassRequest(body, modelStr, userAgent, !!settings.ccFilterNaming);
  if (bypassResponse) return bypassResponse.response || bypassResponse;

View on GitHub (pinned to 90b52e06ff)

Solutions

  1. Add the key: set Authorization: Bearer <your-9router-api-key> (or x-api-key) on every request.
  2. Configure your OpenAI SDK client with apiKey: 'your-9router-key' — never leave it empty when requireApiKey is on.
  3. If local-only usage is intended, disable requireApiKey in the dashboard settings (Settings → API key enforcement).
  4. Verify which header extractApiKey reads for your client and that a proxy is not stripping Authorization before it reaches the gateway.

Example fix

// before
const client = new OpenAI({ baseURL: 'http://localhost:20128/v1' });

// after
const client = new OpenAI({
  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('NINE_ROUTER_API_KEY is not set; gateway has requireApiKey enabled');
headers['Authorization'] = `Bearer ${apiKey}`;

Type guard

function hasApiKey(headers) {
  const auth = headers['authorization'] || '';
  return /^Bearer\s+\S+/.test(auth) || Boolean(headers['x-api-key']);
}

Try / catch

const res = await fetch(url, { headers });
if (res.status === 401 && (await res.text()).includes('Missing API key')) {
  throw new Error('Gateway requires an API key: set Authorization: Bearer <key>');
}

Prevention

When it happens

Trigger: POST to /v1/chat/completions with settings.requireApiKey=true and no Authorization header (or no x-api-key header) on the request.

Common situations: User enabled 'require API key' in the dashboard after the client was already configured without a key; SDK default (e.g. OpenAI SDK) silently omitting the key because baseURL was set but apiKey left empty; calling the endpoint from a browser or script without auth headers.

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


AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30). Data as JSON: /api/errors/f034cb0ba4d7b3e9. Report an issue: GitHub.