Repository navigation
fix(combo): lock GitHub models rejected as "not supported" for future requests - #11781
Merged
diegosouzapw merged 2 commits intoAug 29, 2026
Conversation
… requests Same bug class as diegosouzapw#11762/diegosouzapw#11774: a permanent-for-this-account 400 ("The requested model is not supported." / "not available for integrator 'vscode-chat'") was never recorded as a model lockout, because combo's per-request same-model retry lockout only fires for [408,429,500,502,503,504] statuses — 400 is deliberately excluded there. The diegosouzapw#5249 guard correctly lets combo advance to the next target within the SAME request, but nothing persisted the failure across SEPARATE requests, so the identical dead GitHub model got retried on every single future auto-combo request, forever (observed in production logs: every request wasted several upstream 400 calls on gpt-5.4, gpt-5.5, gpt-5.6-luna/sol/terra, gpt-5.3-codex, mai-code-1-flash — all day). Add an explicit lockModelIfPerModelQuota() call when isModelScoped400(errorText) is true, right after the existing diegosouzapw#2101 stop-guard. github already has per-model-quota enabled, so this locks only the specific model (not the whole connection) for 1h; isModelLocked() is already checked before dispatch on every future request, so the lockout is honored automatically. The in-request combo-advance behavior (diegosouzapw#5249) is unchanged. Also fixes tests/unit/combo-model-scoped-400-advance.test.ts: its sub-tests reused the same model name without clearing lockout streused the same model name without clearing lockout streused the same model nacross sub-tests within the same process — added a clearAllModelLockouts() beforeEach.
…ker tap.testFiles
diegosouzapw
pushed a commit
that referenced
this pull request
Aug 29, 2026
…EADME (#11772) Finishes the Freepik → Magnific rebrand from #10594 across 40 locale files and 3 README feature-list bullets (README.md, docs/i18n/it, docs/i18n/tr) — legacy `freepik` alias intentionally left in code/tests/redirects for backward compatibility, and historical CHANGELOG entries left untouched as documented history. The README bullet had base-drifted since the PR branched (release tip's "What's New" changelog snippet had already dropped two providers mentioned nowhere else in the codebase, unrelated to this PR's scope) — resolved by keeping the tip's current bullet shape and applying only the Freepik→Magnific rename on top, in both the combined-worktree validation and the pushed branch. Validated: all 40 edited locale JSON files parse; re-verified after resync onto the updated tip (post #11762/#11774/#11781).
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
… requests (diegosouzapw#11781) Follow-up to diegosouzapw#11762/diegosouzapw#11774, same bug class in combo's own model-lockout wiring: GitHub rejects several models (gpt-5.4, gpt-5.3-codex, etc.) with a 400 that's permanently unavailable for this account's Copilot integration, but nothing recorded a cross-request lockout — combo's diegosouzapw#5249 in-request advance guard is correct but doesn't persist, so the same doomed model gets retried from scratch on every new request, indefinitely. Fix: on a model-scoped 400 (`isModelScoped400`), call `lockModelIfPerModelQuota(provider, connectionId, rawModel, "model_capacity", 1h)`. GitHub already has per-model-quota enabled, so only the rejected model locks — siblings keep working. `isModelLocked()` is already checked pre-dispatch, so no other wiring needed. Validated: 3/3 new tests + fixed a pre-existing test-isolation gap in combo-model-scoped-400-advance.test.ts (shared model name across sub-tests without clearing lockout state). Thanks!
muhamadgalihsaputra
pushed a commit
to niyatna/NiyatnaRoute
that referenced
this pull request
Sep 27, 2026
…EADME (diegosouzapw#11772) Finishes the Freepik → Magnific rebrand from diegosouzapw#10594 across 40 locale files and 3 README feature-list bullets (README.md, docs/i18n/it, docs/i18n/tr) — legacy `freepik` alias intentionally left in code/tests/redirects for backward compatibility, and historical CHANGELOG entries left untouched as documented history. The README bullet had base-drifted since the PR branched (release tip's "What's New" changelog snippet had already dropped two providers mentioned nowhere else in the codebase, unrelated to this PR's scope) — resolved by keeping the tip's current bullet shape and applying only the Freepik→Magnific rename on top, in both the combined-worktree validation and the pushed branch. Validated: all 40 edited locale JSON files parse; re-verified after resync onto the updated tip (post diegosouzapw#11762/diegosouzapw#11774/diegosouzapw#11781).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Follow-up to #11762 / #11774 — same bug class, this time in combo's own model routing
Checking a fresh 1h log confirmed another instance of the "permanent failure never gets locked out, so it's retried forever" bug — this time not in
checkFallbackError's classification, but incombo.ts's own model-lockout wiring.The symptom
githubrejects several models with a 400 that is permanent for this account's Copilot integration — it will never start working mid-session:This isn't a one-off — the same models (
gpt-5.3-codex,gpt-5.4,gpt-5.4-mini,gpt-5.5,gpt-5.6-luna,gpt-5.6-sol,gpt-5.6-terra,mai-code-1-flash) get rejected with this exact 400 on every singlevirtual-auto-default-*-githubcombo step, in every request, for the entire hour (dozens of times across the log). Each occurrence is a wasted upstream call.Root cause
Combo's #5249 guard (
isModelScoped400) correctly lets the combo advance to the next target within the same request — that's intentional and correct, since a different provider might serve the model. But nothing ever recorded a cross-request lockout for the rejected model, because the per-request "same-model retry" lockout path incombo.ts(recordModelLockoutFailure, gated byisTransient) only fires for[408, 429, 500, 502, 503, 504]— 400 is deliberately excluded there (a 400 always advances immediately, never retries the same model in-request). So a model that GitHub will reject forever for this account gets tried again from scratch on every new incoming request, indefinitely.The fix
In
open-sse/services/combo.ts, right after the existing #2101/#5249 stop-guard: whenisModelScoped400(errorText)is true, calllockModelIfPerModelQuota(provider, connectionId, rawModel, "model_capacity", 1h).githubalready has per-model-quota enabled (hasPerModelQuota("github") === true), so this locks only the rejected model, not the whole GitHub connection — sibling models keep working normally.isModelLocked()is already checked before dispatch on every future request (combo.tspre-check), so the lockout is honored automatically — no other wiring needed.Testing
Added
tests/unit/github-model-not-supported-lockout.test.ts(3 tests, all passing):isModelScoped400matches both GitHub phrasings from the logs.githubconfirmed as a per-model-quota provider.lockModelIfPerModelQuotalocks the rejected model while leaving a sibling model on the same connection eligible.Also fixed
tests/unit/combo-model-scoped-400-advance.test.ts: its sub-tests reuse the same model name (github/claude-fable-5) across severaltest()blocks without clearing lockout state — with the new persistent lockout, the first sub-test's 400 now (correctly) locks that model, causing later sub-tests in the same process to skip it. Added aclearAllModelLockouts()beforeEachto keep each sub-test isolated; no behavioral assertions changed.Ran locally:
Also registered the new test in
stryker.conf.json'stap.testFiles(required for themutation-test-coveragegate, per CI feedback on #11762).Files changed
open-sse/services/combo.ts— newlockModelIfPerModelQuotaimport + call at the model-scoped-400 site.tests/unit/github-model-not-supported-lockout.test.ts— new regression test.tests/unit/combo-model-scoped-400-advance.test.ts— added lockout-state isolation between sub-tests.stryker.conf.json— register the new test file.