{"record":{"id":"da337590ce05ab7e","repo":"santifer/career-ops","slug":"models-failed-to-fetch-free-model-list-reason","errorCode":null,"errorMessage":"[models] Failed to fetch free model list: ${reason}. Check that your API key is valid and that network access to OpenRouter is available.","messagePattern":"\\[models\\] Failed to fetch free model list: (.+?)\\. Check that your API key is valid and that network access to OpenRouter is available\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"openrouter-runner.mjs","lineNumber":140,"sourceCode":"    if (list.length === 0) throw new Error('No free models found in API response');\n\n    // Sort by provider priority; within the same provider sort alphabetically\n    function providerOf(id) { return id.split('/')[0]; }\n    function priorityOf(id) {\n      const idx = PROVIDER_PRIORITY.indexOf(providerOf(id));\n      return idx === -1 ? PROVIDER_PRIORITY.length : idx;\n    }\n\n    freeModels = list.sort((a, b) => {\n      const diff = priorityOf(a) - priorityOf(b);\n      return diff !== 0 ? diff : a.localeCompare(b);\n    });\n\n    console.log(`[models] ${freeModels.length} free models loaded from OpenRouter API.`);\n  } catch (e) {\n    const reason = e instanceof Error ? e.message : String(e);\n    const hasKey = Boolean(process.env.OPENROUTER_API_KEY);\n    throw new Error(\n      `[models] Failed to fetch free model list: ${reason}. ` +\n      (hasKey ? 'Check that your API key is valid and that network access to OpenRouter is available.'\n               : 'OPENROUTER_API_KEY is not set — copy .env.example to .env and add your key.')\n    );\n  }\n\n  return freeModels;\n}\n\n// List and exit (helper command)\nasync function cmdModels() {\n  const models = await loadFreeModels();\n  console.log(`\\nFree models available on OpenRouter (${models.length} total):\\n`);\n  models.forEach((id, i) => console.log(`  ${String(i + 1).padStart(2)}. ${id}`));\n  console.log('');\n}\n\n// ---------------------------------------------------------------------------","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/santifer/career-ops/blob/9b17a8ac97b398a496b38e423ae24e433b43254f/openrouter-runner.mjs#L122-L158","documentation":"Thrown by loadFreeModels() in openrouter-runner.mjs when fetching the OpenRouter /models endpoint to build the free-model list fails. The catch inspects the underlying error message and branches the hint: if OPENROUTER_API_KEY is set it suggests the key is invalid or network access is blocked; if the key is missing it points to copying .env.example. This is a startup precondition — without the model list, model rotation cannot proceed.","triggerScenarios":"Any exception during the fetch/sort of the OpenRouter models list: HTTP 401/403 (bad key), network/DNS failure, OpenRouter API outage, rate limiting, or a malformed JSON response. The catch wraps the original reason into this message.","commonSituations":"OPENROUTER_API_KEY expired or revoked; corporate firewall/CI blocking openrouter.ai; .env not loaded; OpenRouter temporarily down; free-tier quota exhausted returning an error payload.","solutions":["Confirm OPENROUTER_API_KEY is set and valid: `curl -H \"Authorization: Bearer $OPENROUTER_API_KEY\" https://openrouter.ai/api/v1/models`.","Ensure .env is loaded (copy .env.example to .env, add key from https://openrouter.ai) and the runner sources it.","Check network egress to openrouter.ai from the host/CI (no proxy block, DNS resolves).","If OpenRouter is having an outage, retry shortly; if the free list is genuinely empty for your account, pin a model via CAREER_OPS_MODEL to bypass loadFreeModels."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"// Smoke-test the OpenRouter models endpoint before launching a batch\nconst ok = await fetch('https://openrouter.ai/api/v1/models', {\n  headers: { Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}` }\n}).then(r => r.ok).catch(() => false);\nif (!ok) { console.error('OpenRouter /models unreachable — fix key/network before batch'); process.exit(1); }","typeGuard":null,"tryCatchPattern":"try {\n  const models = await loadFreeModels();\n} catch (e) {\n  if (e.message.startsWith('[models] Failed to fetch free model list')) {\n    // fall back to a pinned model so the run can proceed\n    process.env.CAREER_OPS_MODEL = 'google/gemini-2.0-flash-exp:free';\n  } else throw e;\n}","preventionTips":["Load .env explicitly and assert OPENROUTER_API_KEY is set at startup.","Add a reachability check for openrouter.ai in CI before running evaluations.","Pin CAREER_OPS_MODEL as a fallback so a /models outage doesn't block the whole run.","Distinguish key-missing (set the env) from network-blocked (fix egress) using the message suffix."],"tags":["network","api","configuration","openrouter","startup"],"backgroundTag":null,"analyzedSha":"9b17a8ac97b398a496b38e423ae24e433b43254f","analyzedAt":"2026-08-13T00:48:39.135Z","schemaVersion":2},"datasetVersion":"2026-08-13T04:17:16.726Z"}