santifer/career-ops · error · Error
[models] Failed to fetch free model list: ${reason}. Check t
Error message
[models] Failed to fetch free model list: ${reason}. Check that your API key is valid and that network access to OpenRouter is available. What it means
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.
Source
Thrown at openrouter-runner.mjs:140
if (list.length === 0) throw new Error('No free models found in API response');
// Sort by provider priority; within the same provider sort alphabetically
function providerOf(id) { return id.split('/')[0]; }
function priorityOf(id) {
const idx = PROVIDER_PRIORITY.indexOf(providerOf(id));
return idx === -1 ? PROVIDER_PRIORITY.length : idx;
}
freeModels = list.sort((a, b) => {
const diff = priorityOf(a) - priorityOf(b);
return diff !== 0 ? diff : a.localeCompare(b);
});
console.log(`[models] ${freeModels.length} free models loaded from OpenRouter API.`);
} catch (e) {
const reason = e instanceof Error ? e.message : String(e);
const hasKey = Boolean(process.env.OPENROUTER_API_KEY);
throw new Error(
`[models] Failed to fetch free model list: ${reason}. ` +
(hasKey ? 'Check that your API key is valid and that network access to OpenRouter is available.'
: 'OPENROUTER_API_KEY is not set — copy .env.example to .env and add your key.')
);
}
return freeModels;
}
// List and exit (helper command)
async function cmdModels() {
const models = await loadFreeModels();
console.log(`\nFree models available on OpenRouter (${models.length} total):\n`);
models.forEach((id, i) => console.log(` ${String(i + 1).padStart(2)}. ${id}`));
console.log('');
}
// ---------------------------------------------------------------------------View on GitHub (pinned to 9b17a8ac97)
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.
Defensive patterns
Strategy: fallback
Validate before calling
// Smoke-test the OpenRouter models endpoint before launching a batch
const ok = await fetch('https://openrouter.ai/api/v1/models', {
headers: { Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}` }
}).then(r => r.ok).catch(() => false);
if (!ok) { console.error('OpenRouter /models unreachable — fix key/network before batch'); process.exit(1); } Try / catch
try {
const models = await loadFreeModels();
} catch (e) {
if (e.message.startsWith('[models] Failed to fetch free model list')) {
// fall back to a pinned model so the run can proceed
process.env.CAREER_OPS_MODEL = 'google/gemini-2.0-flash-exp:free';
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- OPENROUTER_API_KEY not found. Copy .env.example to .env and
- HTTP ${resp.status}: ${t.slice(0, 120)}
- Pinned model timed out after ${MODEL_TIMEOUT_MS / 1000}s
- No free OpenRouter models are available. Model loading may h
- Timeout after ${MODEL_TIMEOUT_MS / 1000}s
AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13).
Data as JSON: /api/errors/da337590ce05ab7e.
Report an issue: GitHub.