decolua/9router · error
${msg} (lastError or "All combo models unavailable")
Error message
${msg} (lastError or "All combo models unavailable") What it means
Every model in the combo failed with fallback-eligible errors. The handler aggregates lastError, the earliest Retry-After across members, and returns unavailableResponse(status, msg, ...) where msg is lastError or the default 'All combo models unavailable'. Status is 503 when the last error mentions 'no credentials', otherwise the first recorded member status or 503. This variant fires when a Retry-After hint exists.
Source
Thrown at open-sse/services/combo.js:373
} catch (error) {
// Catch unexpected exceptions to ensure fallback continues
lastError = error.message || String(error);
if (!lastStatus) lastStatus = 500;
log.warn("COMBO", `Model ${modelStr} threw error, trying next`, { error: lastError });
}
}
// All models failed
// Use 503 (Service Unavailable) rather than 406 (Not Acceptable) — 406 implies
// the request itself is invalid, but here the providers are simply unavailable
// or have no active credentials. 503 is more accurate and retryable by clients.
const allDisabled = lastError && lastError.toLowerCase().includes("no credentials");
const status = allDisabled ? 503 : (lastStatus || 503);
const msg = lastError || "All combo models unavailable";
if (earliestRetryAfter) {
const retryHuman = formatRetryAfter(earliestRetryAfter);
log.warn("COMBO", `All models failed | ${msg} (${retryHuman})`);
return unavailableResponse(status, msg, earliestRetryAfter, retryHuman);
}
log.warn("COMBO", `All models failed | ${msg}`);
return new Response(
JSON.stringify({ error: { message: msg } }),
{ status, headers: { "Content-Type": "application/json" } }
);
}
/**
* Extract assistant text from a non-stream completion across formats
* (OpenAI chat, Claude messages, Gemini, OpenAI Responses). Returns "" if none.
* Panel responses are already translated to the client format by chatCore, so the
* leaf content→string step reuses the translator's own extractTextContent.
*/
function extractPanelText(json) {
if (!json || typeof json !== "object") return "";View on GitHub (pinned to 90b52e06ff)
Solutions
- Wait until the Retry-After time in the response before retrying.
- Check the specific msg in the response — it identifies which member error came last/first; fix that credential or account.
- Add independent credentials (different providers/keys) to the combo so members don't share a quota.
- Verify each combo model id is valid and its account is active in the dashboard.
- Add client-side exponential backoff instead of immediate retries, which extend the rate-limit lock.
Defensive patterns
Strategy: retry
Try / catch
const res = await chat({ model: comboName, ... });
if (res.status === 503 && res.headers.get('retry-after')) {
const waitMs = Number(res.headers.get('retry-after')) * 1000;
await new Promise(r => setTimeout(r, waitMs));
return retryWithBackoff(chat);
} Prevention
- Ensure combo members use independent credentials so quotas don't fail together.
- Honor the returned retryAfter timestamp before any retry.
- Monitor per-key quota consumption and pre-warm alternate accounts.
- Spread search bursts across time instead of parallel fan-out.
When it happens
Trigger: All combo members rate-limited or out of credentials (each returns 429/503 with retryAfter); handleComboChat iterated every rotated model and none returned result.ok; combo members share the same underlying quota (same key, same upstream) so they fail together.
Common situations: Combo of aliases all backed by one provider key that hit its rate limit; all member accounts disabled or expired; provider-wide outage during peak hours; the combo configured before member credentials were ever set up.
Related errors
- [${providerId}] ${errorMsg}
- [${providerId}] ${errorMsg}
- All accounts unavailable
- MiMo bootstrap failed: ${response.status}
- NanoBanana status ${r.status}
AI-assisted analysis of decolua/9router@90b52e06ff (2026-08-30).
Data as JSON: /api/errors/5446170820463cc4.
Report an issue: GitHub.