santifer/career-ops · critical · Error

All ${active.length} active models failed. Last error: ${las

Error message

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

What it means

Thrown by callOpenRouter() after the rotation loop has tried every active (non-blacklisted) model and none succeeded. This is the terminal failure for the rotation path: lastError holds the most recent exception from the final attempt, and its message is appended so the caller knows the underlying cause (HTTP error, timeout, empty response, etc.).

Source

Thrown at openrouter-runner.mjs:345

        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 9b17a8ac97)

Solutions

  1. Read lastError.message in the thrown text — it identifies the systemic cause (401/429/timeout) to fix first.
  2. For 401: fix/regenerate OPENROUTER_API_KEY (error 68).
  3. For 429s across all models: wait and reduce request rate; consider pinning one model and backing off.
  4. For network errors: verify egress to openrouter.ai from the host/CI and retry.
  5. For an OpenRouter outage: check status.openrouter.ai and retry later.
Defensive patterns

Strategy: try-catch

Try / catch

try {
  return await callOpenRouter(systemPrompt, userMessage);
} catch (e) {
  if (e.message.startsWith('All ') && e.message.includes('active models failed')) {
    // systemic failure — read the embedded lastError to decide: key, network, or outage
    if (e.message.includes('HTTP 401')) {
      throw new Error('OpenRouter key invalid — set OPENROUTER_API_KEY');
    }
    if (e.message.includes('HTTP 429')) {
      // back off and retry after a delay
      await new Promise(r => setTimeout(r, 5000));
      return await callOpenRouter(systemPrompt, userMessage);
    }
  }
  throw e;
}

Prevention

When it happens

Trigger: The for-loop over `active` models exhausted every model (attempt went 0..active.length-1) without a successful return — each iteration threw and was caught, updating lastError. Happens when a systemic issue (bad key, network outage, account/region problem, all models rate-limited) affects every model.

Common situations: OPENROUTER_API_KEY revoked/expired (401 on every model); network egress to openrouter.ai blocked from CI; sustained rate-limiting across all free models; OpenRouter-wide outage; account suspended or out of free-tier quota.

Related errors


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