{"record":{"id":"d7c185f43e49fa73","repo":"santifer/career-ops","slug":"openrouter-api-key-not-found-copy-env-example-to","errorCode":null,"errorMessage":"OPENROUTER_API_KEY not found.\nCopy .env.example to .env and add your API key.\nFree key: https://openrouter.ai","messagePattern":"OPENROUTER_API_KEY not found\\.\nCopy \\.env\\.example to \\.env and add your API key\\.\nFree key: https://openrouter\\.ai","errorType":"validation","errorClass":"Error","httpStatus":null,"severity":"critical","filePath":"openrouter-runner.mjs","lineNumber":201,"sourceCode":"// Providers that support caching (Anthropic, Gemini, …) reuse the prefix across\n// back-to-back calls within the cache TTL; providers that don't simply ignore\n// the field, so this is a safe passthrough that never changes the prompt text.\nexport function buildCachedSystemMessage(systemPrompt) {\n  return {\n    role: 'system',\n    content: [\n      { type: 'text', text: systemPrompt, cache_control: { type: 'ephemeral' } },\n    ],\n  };\n}\n\n// ---------------------------------------------------------------------------\n// OpenRouter API call — automatic model rotation with fallback\n// ---------------------------------------------------------------------------\nasync function callOpenRouter(systemPrompt, userMessage) {\n  const key = process.env.OPENROUTER_API_KEY;\n  if (!key) {\n    throw new Error(\n      'OPENROUTER_API_KEY not found.\\n' +\n      'Copy .env.example to .env and add your API key.\\n' +\n      'Free key: https://openrouter.ai'\n    );\n  }\n\n  const pinnedModel = process.env.CAREER_OPS_MODEL;\n  if (pinnedModel) {\n    activeModel = pinnedModel;\n    process.stdout.write(`[model] ${pinnedModel} (pinned) ... `);\n    const body = JSON.stringify({\n      model: pinnedModel,\n      messages: [\n        buildCachedSystemMessage(systemPrompt),\n        { role: 'user', content: userMessage },\n      ],\n      max_tokens: MAX_TOKENS,\n    });","sourceCodeStart":183,"sourceCodeEnd":219,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/openrouter-runner.mjs#L183-L219","documentation":"Thrown by callOpenRouter() in openrouter-runner.mjs when process.env.OPENROUTER_API_KEY is falsy at call time. This is the hard precondition before any HTTP request — there is no fallback, no anonymous access. The message directs the user to copy .env.example to .env and obtain a free key from openrouter.ai.","triggerScenarios":"Running the runner without OPENROUTER_API_KEY in the environment: .env missing, .env not loaded by the runner, key line commented out, or running in a shell/CI that didn't export it.","commonSituations":"Fresh clone without .env; CI secret not configured; renamed key; running via a wrapper that strips env; key set in a different shell than the one invoking the runner.","solutions":["Copy .env.example to .env and add your key: OPENROUTER_API_KEY=sk-or-v1-...","Get a free key at https://openrouter.ai if you don't have one.","Verify it's visible: `node -e \"console.log(Boolean(process.env.OPENROUTER_API_KEY))\"` after loading .env, or export it directly in the shell.","In CI, set the OPENROUTER_API_KEY secret on the job."],"exampleFix":"# before: .env missing or empty\n\n# after: .env\nOPENROUTER_API_KEY=sk-or-v1-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx","handlingStrategy":"validation","validationCode":"if (!process.env.OPENROUTER_API_KEY) {\n  throw new Error('Missing OPENROUTER_API_KEY. Copy .env.example to .env and add your key from https://openrouter.ai');\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always ship a .env (gitignored) with OPENROUTER_API_KEY; never rely on it being inherited.","In CI, set OPENROUTER_API_KEY as a repository secret on every job that calls the runner.","Add a startup assertion so a missing key fails fast with a clear message.","Rotate keys via the OpenRouter dashboard; don't hardcode."],"tags":["configuration","openrouter","secrets","startup","api"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}