santifer/career-ops · error · Error

No free OpenRouter models are available. Model loading may h

Error message

No free OpenRouter models are available. Model loading may have failed, or your account currently has no free models.

What it means

Thrown by callOpenRouter() after loadFreeModels() returns an empty array — the model list loaded but contained zero free models. This is distinct from a fetch failure (error 67): the API call succeeded, it just yielded nothing usable. Without any models, the rotation loop has nothing to iterate, so it fails immediately.

Source

Thrown at openrouter-runner.mjs:257

      if (data.error) throw new Error(data.error.message);
      const content = data.choices?.[0]?.message?.content ?? '';
      if (!content) throw new Error('Empty response');
      console.log('OK');
      const usage = normalizeOpenAIUsage(data.usage);
      return { content, usage };
    } catch (e) {
      if (e.name === 'AbortError') throw new Error(`Pinned model timed out after ${MODEL_TIMEOUT_MS / 1000}s`);
      throw e;
    } finally {
      clearTimeout(timerId);
    }
  }

  const models = await loadFreeModels();
  let lastError;

  if (models.length === 0) {
    throw new Error(
      'No free OpenRouter models are available. Model loading may have failed, or your account currently has no free models.'
    );
  }
  // Build the active (non-blacklisted) model list in rotation order
  const active = models.filter(m => !blacklistedModels.has(m));
  if (active.length === 0) throw new Error('All loaded models have been blacklisted this session.');

  for (let attempt = 0; attempt < active.length; attempt++) {
    const model = active[(modelIndex % active.length + attempt) % active.length];
    activeModel = model;
    process.stdout.write(`[model] ${model} ... `);

    try {
      const body = JSON.stringify({
        model,
        messages: [
          buildCachedSystemMessage(systemPrompt),
          { role: 'user', content: userMessage },

View on GitHub (pinned to 9b17a8ac97)

Solutions

  1. Pin a specific known-good free model via CAREER_OPS_MODEL to bypass the list entirely (e.g. google/gemini-2.0-flash-exp:free).
  2. Re-run loadFreeModels (the empty list is often transient) or check https://openrouter.ai/models?max_price=0 for current free models.
  3. Check your OpenRouter account standing — some account states lose free-tier access.
  4. If the loader filter is the culprit, update the free-model detection in loadFreeModels.

Example fix

# before — empty free list
node openrunner-runner.mjs ...
# throws: No free OpenRouter models are available.

# after — pin a known free model
export CAREER_OPS_MODEL=google/gemini-2.0-flash-exp:free
Defensive patterns

Strategy: fallback

Validate before calling

const freeCount = await loadFreeModels().then(m => m.length).catch(() => -1);
if (freeCount === 0) {
  process.env.CAREER_OPS_MODEL = 'google/gemini-2.0-flash-exp:free';
}

Try / catch

try {
  return await callOpenRouter(systemPrompt, userMessage);
} catch (e) {
  if (e.message.startsWith('No free OpenRouter models are available')) {
    process.env.CAREER_OPS_MODEL = 'google/gemini-2.0-flash-exp:free';
    return await callOpenRouter(systemPrompt, userMessage);
  }
  throw e;
}

Prevention

When it happens

Trigger: loadFreeModels() returns []: OpenRouter's /models endpoint answered 2xx but no models matched the free-tier filter, or the account/region currently has no free models available. The `if (models.length === 0)` guard throws before rotation.

Common situations: OpenRouter changed its free-tier offering and the filter matches nothing; account in a region with no free models; transient empty response from /models; the free model ids changed naming and the loader's filter no longer matches.

Related errors


AI-assisted analysis of santifer/career-ops@9b17a8ac97 (2026-08-13). Data as JSON: /api/errors/1a187bb0a9d29d91. Report an issue: GitHub.