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

  1. Read the embedded `reason` after the colon — it is the real cause (HTTP status, JSON error, etc.).
  2. If the message says OPENROUTER_API_KEY is not set: `cp .env.example .env` and add a key from https://openrouter.ai/keys.
  3. If a key is set: verify it is valid and that the machine can reach openrouter.ai (curl the models endpoint).
  4. Ensure your dotenv loading actually runs before this module — a key set only in .env but not loaded still counts as unset.
  5. 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

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


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)