{"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":"validation","errorClass":"ServerClassifiedProviderError","httpStatus":null,"severity":"error","filePath":"src/server/generation/providers/OpenRouterObservationProvider.ts","lineNumber":55,"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 ?? OPENROUTER_APP_URL;\n    this.appName = options.appName ?? OPENROUTER_APP_TITLE;\n    this.fetchImpl = options.fetchImpl ?? fetch;\n  }\n\n  async generate(\n    context: ServerGenerationContext,\n    signal?: AbortSignal,\n  ): Promise<ServerGenerationResult> {","sourceCodeStart":37,"sourceCodeEnd":73,"githubUrl":"https://github.com/thedotmack/claude-mem/blob/d8bc9755e74915e5c3b999181e10a67c889bce2a/src/server/generation/providers/OpenRouterObservationProvider.ts#L37-L73","documentation":"The OpenRouter provider's constructor rejects instantiation when `options.apiKey` is falsy, throwing a ServerClassifiedProviderError with kind 'auth_invalid'. OpenRouter requires a Bearer key for every request, so the provider fails fast rather than sending doomed requests. Raised from the constructor, so the app crashes at wiring time.","triggerScenarios":"Constructing `new OpenRouterObservationProvider({...})` with `apiKey` undefined, null, or empty string — typically because the OPENROUTER_API_KEY environment variable is unset or the wrong config key was read.","commonSituations":"OPENROUTER_API_KEY not set in the deployment environment; .env file not loaded; key stored under a different env name than the code reads; secrets manager returning undefined for a missing entry; refactoring renamed the option field without updating call sites.","solutions":["Set OPENROUTER_API_KEY in the environment or deployment secrets","Trace where the options object is built and confirm the correct env var/config key is read and non-empty","Add a startup config check that fails with a clear message listing required provider keys","Verify .env loading (dotenv/similar) runs before any provider construction"],"exampleFix":"// before\nconst provider = new OpenRouterObservationProvider({ apiKey: config.openrouter?.key });\n\n// after\nconst apiKey = process.env.OPENROUTER_API_KEY;\nif (!apiKey) throw new Error('OPENROUTER_API_KEY is required');\nconst provider = new OpenRouterObservationProvider({ apiKey });","handlingStrategy":"validation","validationCode":"const apiKey = process.env.OPENROUTER_API_KEY;\nif (typeof apiKey !== 'string' || apiKey.trim() === '') {\n  throw new Error('OPENROUTER_API_KEY must be set to a non-empty string');\n}\nconst provider = new OpenRouterObservationProvider({ apiKey });","typeGuard":"function hasOpenRouterKey(o: OpenRouterObservationProviderOptions): o is OpenRouterObservationProviderOptions & { apiKey: string } {\n  return typeof o.apiKey === 'string' && o.apiKey.trim().length > 0;\n}","tryCatchPattern":"try {\n  provider = new OpenRouterObservationProvider({ apiKey });\n} catch (e) {\n  if (e instanceof ServerClassifiedProviderError && e.kind === 'auth_invalid') {\n    throw new ConfigError('OpenRouter provider misconfigured: apiKey missing. Set OPENROUTER_API_KEY.');\n  }\n  throw e;\n}","preventionTips":["Run a startup config check that lists all missing provider credentials at once","Keep OPENROUTER_API_KEY in .env.example and deployment secrets templates","Ensure dotenv/secret loading happens before provider construction","Trim and type-check key values read from config sources"],"tags":["api-key","authentication","configuration","openrouter"],"backgroundTag":"missing-api-key","analyzedSha":"d8bc9755e74915e5c3b999181e10a67c889bce2a","analyzedAt":"2026-09-17T16:40:26.182Z","contentChangedAt":"2026-09-17T16:40:26.182Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}