santifer/career-ops · error · Error
[models] Failed to fetch free model list
Error message
[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.')} What it means
Wrapping error thrown by loadFreeModels()'s catch block: any failure inside the fetch/parse/filter sequence (including errors 91/92) is rethrown with the `[models]` prefix, the original reason, and context-dependent advice — a key-validation hint if OPENROUTER_API_KEY is set, or a setup hint if it is missing. This is the error a caller actually sees; the original cause is embedded in the message.
Solutions
- Read the embedded `reason` after the colon — it is the real cause (HTTP status, JSON error, etc.).
- If the message says OPENROUTER_API_KEY is not set: `cp .env.example .env` and add a key from https://openrouter.ai/keys.
- If a key is set: verify it is valid and that the machine can reach openrouter.ai (curl the models endpoint).
- Ensure your dotenv loading actually runs before this module — a key set only in .env but not loaded still counts as unset.
- On transient network errors, retry; on persistent 5xx, check OpenRouter status.
Defensive patterns
Strategy: try-catch
Validate before calling
if (!process.env.OPENROUTER_API_KEY) {
throw new Error('Setup required: cp .env.example .env and add OPENROUTER_API_KEY from https://openrouter.ai');
} Try / catch
try {
await runEvaluation();
} catch (err) {
if (String(err.message).startsWith('[models]')) {
console.error('OpenRouter model list problem:', err.message);
console.error('Fix the root cause shown after the colon, then retry.');
} else throw err;
} Prevention
- Load .env (dotenv) before importing any runner module.
- Pre-flight check the key with a cheap authenticated request at startup.
- Keep the wrapped reason visible in logs — it names the real failure.
- Distinguish the no-key vs bad-key branches when writing runbooks.
When it happens
Trigger: Any of: HTTP error from the models endpoint (see err 91), JSON parse failure of the response, `data.data` missing/undefined, or an empty free-model list — all caught and re-wrapped by line 152.
Common situations: No .env file (key undefined → second message branch); invalid key (401 → first branch); DNS/network failure; OpenRouter outage; API payload drift.
Understand the failure class
Background: "API request failed": what wrapped HTTP errors from external APIs mean and how to find the real cause — this error's family across 29 libraries.
Related errors
- HTTP
- All active models failed. Last error
- [models] Failed to fetch free model list
- [models] Failed to fetch free model list
- OPENROUTER_API_KEY not found. Copy .env.example to .env and…
AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16).
Data as JSON: /api/errors/1f102006b1983618.
Report an issue: GitHub.
Appendix: source
Thrown at openrouter-runner.mjs:152
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 aac998c7ed)