santifer/career-ops · error · Error

No free OpenRouter models are available. Model loading may…

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 — meaning the model list loaded 'successfully' but contains nothing, so there is no model to call. Distinct from error 92 (which fires inside loadFreeModels when filtering finds nothing): this fires when an empty list reached the caller anyway, e.g. a cached empty list or a future path where loadFreeModels returns [] without throwing.

Solutions

  1. Clear the module-level cache (restart the process) so loadFreeModels refetches from the API.
  2. Run a standalone fetch of the models endpoint to check whether free models actually exist right now.
  3. Check the earlier `[models] Failed to fetch...` log lines — an earlier failure may have poisoned the cache.
  4. If no free models exist for the account/plan, configure paid models and ensure the key has credits.
  5. Harden loadFreeModels so it never caches an empty list as a success value.

Example fix

// before
const freeModels = ...;
if (freeModels !== null) return freeModels;
// after (don't cache empty as success)
const freeModels = ...;
if (freeModels !== null && freeModels.length > 0) return freeModels;
Defensive patterns

Strategy: validation

Validate before calling

const models = await loadFreeModels();
if (!Array.isArray(models) || models.length === 0) {
  throw new Error('No free models available — restart to clear the cache or add credits/paid models.');
}

Type guard

function hasUsableModels(models) {
  return Array.isArray(models) && models.some(m => typeof m === 'string' && m.length > 0);
}

Try / catch

try {
  result = await callOpenRouter(systemPrompt, userMessage);
} catch (err) {
  if (err.message.startsWith('No free OpenRouter models')) {
    console.error('Model list empty: restart the process to force a refetch, or switch to paid models.');
    process.exit(1);
  }
  throw err;
}

Prevention

When it happens

Trigger: `await loadFreeModels()` resolves to [] — a previously cached empty result, or a code path where the fetch failure was swallowed and [] returned; callOpenRouter then aborts before building the rotation list.

Common situations: Session-level cache holding an empty list from a failed first load; test/mocked environment returning []; OpenRouter genuinely listing no free models for the account at load time.

Understand the failure class

Background: EmptyResultError / "no results found": when an API or scraper succeeds but returns zero rows — this error's family across 9 libraries.

Related errors


AI-assisted analysis of santifer/career-ops@aac998c7ed (2026-09-16). Data as JSON: /api/errors/1a187bb0a9d29d91. Report an issue: GitHub.

Appendix: source

Thrown at openrouter-runner.mjs:280

      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 aac998c7ed)