{"record":{"id":"ba9457800973d837","repo":"thedotmack/claude-mem","slug":"auth-invalid-ba9457","errorCode":"auth_invalid","errorMessage":"OpenRouter API key not configured","messagePattern":"OpenRouter API key not configured","errorType":"exception","errorClass":"ServerClassifiedProviderError","httpStatus":null,"severity":"error","filePath":"src/server/generation/providers/OpenRouterObservationProvider.ts","lineNumber":53,"sourceCode":"interface OpenRouterResponse {\n  choices?: Array<{ message?: { content?: string } }>;\n  usage?: { total_tokens?: number };\n  error?: { code?: string | number; message?: string };\n}\n\nexport class OpenRouterObservationProvider implements ServerGenerationProvider {\n  readonly providerLabel = 'openrouter' as const;\n  private readonly apiKey: string;\n  private readonly model: string;\n  private readonly apiUrl: string;\n  private readonly maxOutputTokens: number;\n  private readonly siteUrl: string;\n  private readonly appName: string;\n  private readonly fetchImpl: typeof fetch;\n\n  constructor(options: OpenRouterObservationProviderOptions) {\n    if (!options.apiKey) {\n      throw new ServerClassifiedProviderError('OpenRouter API key not configured', {\n        kind: 'auth_invalid',\n        cause: new Error('apiKey is required'),\n      });\n    }\n    this.apiKey = options.apiKey;\n    // Model is passed verbatim so arbitrary OpenAI-compatible ids work. #2393.\n    this.model = options.model ?? DEFAULT_MODEL;\n    this.apiUrl = resolveOpenRouterChatCompletionsUrl(options.baseUrl);\n    this.maxOutputTokens = options.maxOutputTokens ?? 4096;\n    this.siteUrl = options.siteUrl ?? 'https://github.com/thedotmack/claude-mem';\n    this.appName = options.appName ?? 'claude-mem';\n    this.fetchImpl = options.fetchImpl ?? fetch;\n  }\n\n  async generate(\n    context: ServerGenerationContext,\n    signal?: AbortSignal,\n  ): Promise<ServerGenerationResult> {","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d768ba364302d12b76e69e4f021f0bb1d2d50ed6/src/server/generation/providers/OpenRouterObservationProvider.ts#L35-L71","documentation":"Thrown by the OpenRouterObservationProvider constructor when options.apiKey is falsy. It is a ServerClassifiedProviderError with kind 'auth_invalid', so the OpenRouter generation provider refuses to construct without credentials. Model is passed verbatim (per #2393) so arbitrary OpenAI-compatible ids work, but the key itself is mandatory.","triggerScenarios":"Instantiating OpenRouterObservationProvider with an empty/undefined apiKey; the configured provider is 'openrouter' but the key setting is unset; the settings layer resolved the key to an empty string.","commonSituations":"Operator selects openrouter but never exports OPENROUTER_API_KEY. A .env file isn't loaded. The key was revoked at openrouter.ai. Local-dev bypass masks the gap until construction.","solutions":["Set OPENROUTER_API_KEY (or the configured setting) to a valid key from openrouter.ai before launch.","Switch providers if openrouter was selected by mistake.","Verify the settings/env layer resolves the key (check length only).","Re-run after fixing config."],"exampleFix":"// before: no key supplied\nnew OpenRouterObservationProvider({ /* apiKey omitted */ });\n// after\nnew OpenRouterObservationProvider({ apiKey: process.env.OPENROUTER_API_KEY });\n// plus: export OPENROUTER_API_KEY=sk-or-... before launch","handlingStrategy":"validation","validationCode":"function resolveOpenRouterKey(): string {\n  const key = process.env.OPENROUTER_API_KEY ?? readSetting('openRouterApiKey');\n  if (!key || !key.trim()) {\n    throw new Error('OPENROUTER_API_KEY is not set; cannot use the openrouter provider');\n  }\n  return key.trim();\n}","typeGuard":"function hasApiKey(opts: unknown): opts is { apiKey: string } {\n  return typeof (opts as { apiKey?: unknown })?.apiKey === 'string'\n    && (opts as { apiKey: string }).apiKey.trim().length > 0;\n}","tryCatchPattern":"try {\n  provider = new OpenRouterObservationProvider({ apiKey });\n} catch (error) {\n  if (error instanceof ServerClassifiedProviderError && error.kind === 'auth_invalid') {\n    // choose another provider or exit with guidance\n  } else throw error;\n}","preventionTips":["Validate required keys at startup and fail fast with a provider-specific message.","Load .env consistently across environments.","Store keys in a secret manager and detect revocation via a cheap auth probe."],"tags":["auth","openrouter","provider","config","api-key"],"backgroundTag":null,"analyzedSha":"d768ba364302d12b76e69e4f021f0bb1d2d50ed6","analyzedAt":"2026-08-12T23:52:55.241Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}