santifer/career-ops · critical · Error

All active models failed. Last error

Error message

All ${active.length} active models failed. Last error: ${lastError?.message}

What it means

callOpenRouter iterates over the pool of enabled OpenRouter models (after blacklisting), retrying each with rotation on failure. If every active model attempt fails — due to HTTP errors, rate limits, timeouts, or empty responses — it abandons retrying and throws this aggregate error carrying the last underlying error message. It means the LLM call could not be completed by any model in the configured pool, so the caller has no usable completion.

Solutions

  1. Read the 'Last error:' suffix in the message — it names the real cause (e.g. HTTP 401 vs 402 vs 429) and fix that first
  2. Verify OPENROUTER_API_KEY is set and valid, and that the account has credits (OpenRouter dashboard)
  3. Check the configured model names against https://openrouter.ai/models — replace any deprecated slugs
  4. Inspect and reset the persisted model blacklist (saveBlacklist target file); blacklisted models are excluded from 'active' and may leave the pool too small
  5. Confirm outbound network access to openrouter.ai (proxy/firewall/DNS) and retry later if the cause was a transient rate limit

Example fix

// before: single model pool, all fail
MODELS = ['openai/gpt-4o'];

// after: diversify the pool and keep it valid
MODELS = [
  'openai/gpt-4o',
  'anthropic/claude-3.5-sonnet',
  'google/gemini-2.0-flash-001',
];
// plus: export OPENROUTER_API_KEY=sk-or-... (fresh key, funded account)
Defensive patterns

Strategy: retry

Validate before calling

function canAttemptCall() {
  if (!process.env.OPENROUTER_API_KEY) throw new Error('OPENROUTER_API_KEY not set');
  if (activeModels.length === 0) throw new Error('No active models left in pool (all blacklisted?)');
  return true;
}

Try / catch

try {
  const { content } = await callOpenRouter(prompt);
} catch (e) {
  if (e.message.startsWith('All ') && e.message.includes('active models failed')) {
    // inspect lastError suffix: 401/402 → fix key/credits; 429 → back off longer;
    // timeout → shrink prompt. Then retry with fresh models or abort the run.
    console.error('LLM pool exhausted:', e.message.match(/Last error: (.*)/)?.[1]);
  } else throw e;
}

Prevention

When it happens

Trigger: Any callOpenRouter invocation where all models in the active pool fail: OpenRouter API returns non-2xx for every model (401 bad OPENROUTER_API_KEY, 402 insufficient credits, 403 model moderation/availability, 429 persistent rate limit), every request exceeds MODEL_TIMEOUT_MS, every response has data.error set, or every response has an empty choices[0].message.content.

Common situations: Expired or missing OpenRouter API key, exhausted credits, all configured models deprecated/removed from OpenRouter, no network access or corporate proxy blocking openrouter.ai, prompts too large for every model in the pool, or a persistent 429 that blacklisted all models one by one until the pool was empty.

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/8721ca922d62df12. Report an issue: GitHub.

Appendix: source

Thrown at openrouter-runner.mjs:368

        console.log(`SKIP (blacklisted: ${msg})`);
      } else if (is429) {
        rateLimitCounts[model] = (rateLimitCounts[model] ?? 0) + 1;
        if (rateLimitCounts[model] >= 3) {
          blacklistedModels.add(model);
          saveBlacklist(blacklistedModels);
          console.log(`SKIP (auto-blacklisted: persistent 429)`);
        } else {
          console.log(`FAILED (HTTP 429 [${rateLimitCounts[model]}/3])`);
          await new Promise(r => setTimeout(r, 800));
        }
      } else {
        console.log(`FAILED (${msg})`);
        await new Promise(r => setTimeout(r, 800));
      }
    }
  }

  throw new Error(`All ${active.length} active models failed. Last error: ${lastError?.message}`);
}

// ---------------------------------------------------------------------------
// Context loading
// ---------------------------------------------------------------------------
function loadContext() {
  return {
    cv:          readFile('cv.md')               ?? 'CV not found.',
    profile:     readFile('config/profile.yml')  ?? '',
    shared:      readFile('modes/_shared.md')    ?? '',
    profileMode: readFile('modes/_profile.md')   ?? '',
  };
}

export function buildSystemPrompt(modeContent, ctx) {
  const languageInstruction = outputLanguageInstruction(parseOutputLanguage(ctx.profile));
  return [
    ctx.shared,

View on GitHub (pinned to aac998c7ed)