Skip to content

fix(sse): let :free OpenRouter models bypass connection-wide credits_exhausted lock - #10445

Merged
diegosouzapw merged 2 commits into
diegosouzapw:release/v3.8.50from
killmonger2317-coder:fix/openrouter-credit-exhaustion-scope
Aug 15, 2026
Merged

diegosouzapw merged 2 commits into
diegosouzapw:release/v3.8.50from
killmonger2317-coder:fix/openrouter-credit-exhaustion-scope

Conversation

@killmonger2317-coder

Copy link
Copy Markdown
Contributor

Summary

  • A 402 from one paid OpenRouter model correctly locks the whole connection as credits_exhausted for an hour (intentional, per feat(providers): OpenRouter quota tracking #6842's connection-scoped design for OpenRouter's shared account balance). But that lock had no exception for :free-suffixed models, which OpenRouter bills separately from paid credits — so once the lock tripped, every :free model combo target on that same connection was also skipped, defeating failover to configured free models.
  • getProviderCredentials (src/sse/services/auth.ts) now exempts :free model requests from a credits_exhausted OpenRouter connection specifically, while still refusing paid-model requests on that connection and still refusing :free-model requests on connections that are terminal for another reason (banned/expired) or on non-OpenRouter providers.

Test plan

  • TDD: tests/unit/openrouter-free-model-credits-exhausted.test.ts reproduces the bug (fails before the fix), covers the free-model exemption plus 3 guard cases (paid model still blocked, banned connection still blocked, non-OpenRouter provider still blocked). All 4 pass after the fix.
  • node --import tsx/esm --test on related terminal-status/auth/combo suites (auth-terminal-status, openrouter-quota-6842, auth-disable-cooling-2997, quota-connection-recovery, repro-6692-sticky-terminal, repro-7387-sticky-quota-exhausted, combo-pin-health-gate, combo-session-stickiness, sse-auth, startup-stale-cooldown-recovery) — 160/160 pass, no regressions.
  • npx tsc --noEmit -p tsconfig.typecheck-core.json clean on changed files.
  • npx eslint clean on changed files (one pre-existing unrelated violation at auth.ts:128, not touched by this diff).

@diegosouzapw

Copy link
Copy Markdown
Owner

Thank you @killmonger2317-coder — the :free-model exemption on a credits_exhausted OpenRouter connection is a real failover bug, and the 4 tests covering paid/banned/non-openrouter are exactly right. One housekeeping item before merge: this PR targets release/v3.8.49, but the active release branch is release/v3.8.50 — I have retargeted it. Ship 🚀

@diegosouzapw
diegosouzapw changed the base branch from release/v3.8.49 to release/v3.8.50 August 15, 2026 11:35
…exhausted lock

A 402 from one paid OpenRouter model correctly locks the whole connection
as credits_exhausted for an hour (intentional, per diegosouzapw#6842), but that lock
was also blocking every :free model on the same connection even though
OpenRouter bills free models separately from account credits.

Reconstructed clean against release/v3.8.50 by the maintainer: the author's
original branch predated a large auth.ts import refactor; the same delta was
re-applied onto the current tip and the TDD test still passes.

TDD: tests/unit/openrouter-free-model-credits-exhausted.test.ts
reproduces the bug (fails before the fix, passes after) and covers the
three guard cases above.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
@diegosouzapw
diegosouzapw force-pushed the fix/openrouter-credit-exhaustion-scope branch from 199a55a to e29e645 Compare August 15, 2026 12:45
…tryker tap.testFiles

The new unit test covers src/sse/services/auth.ts, which is one of the 31
stryker-mutated modules — per check-mutation-test-coverage every covering
test must be listed in tap.testFiles or its mutant kills stop counting.
Registered the file so the blocking mutation-test-coverage gate passes.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
@diegosouzapw
diegosouzapw merged commit d33e62a into diegosouzapw:release/v3.8.50 Aug 15, 2026
16 checks passed
tkgo11 pushed a commit to tkgo11/OmniRoute that referenced this pull request Sep 23, 2026
…exhausted lock (diegosouzapw#10445)

* fix(sse): let :free OpenRouter models bypass connection-wide credits_exhausted lock

A 402 from one paid OpenRouter model correctly locks the whole connection
as credits_exhausted for an hour (intentional, per diegosouzapw#6842), but that lock
was also blocking every :free model on the same connection even though
OpenRouter bills free models separately from account credits.

Reconstructed clean against release/v3.8.50 by the maintainer: the author's
original branch predated a large auth.ts import refactor; the same delta was
re-applied onto the current tip and the TDD test still passes.

TDD: tests/unit/openrouter-free-model-credits-exhausted.test.ts
reproduces the bug (fails before the fix, passes after) and covers the
three guard cases above.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* test(mutation): register openrouter-free-model-credits-exhausted in stryker tap.testFiles

The new unit test covers src/sse/services/auth.ts, which is one of the 31
stryker-mutated modules — per check-mutation-test-coverage every covering
test must be listed in tap.testFiles or its mutant kills stop counting.
Registered the file so the blocking mutation-test-coverage gate passes.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: killmonger2317-coder <282069920+killmonger2317-coder@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
muhamadgalihsaputra pushed a commit to niyatna/NiyatnaRoute that referenced this pull request Sep 27, 2026
…exhausted lock (diegosouzapw#10445)

* fix(sse): let :free OpenRouter models bypass connection-wide credits_exhausted lock

A 402 from one paid OpenRouter model correctly locks the whole connection
as credits_exhausted for an hour (intentional, per diegosouzapw#6842), but that lock
was also blocking every :free model on the same connection even though
OpenRouter bills free models separately from account credits.

Reconstructed clean against release/v3.8.50 by the maintainer: the author's
original branch predated a large auth.ts import refactor; the same delta was
re-applied onto the current tip and the TDD test still passes.

TDD: tests/unit/openrouter-free-model-credits-exhausted.test.ts
reproduces the bug (fails before the fix, passes after) and covers the
three guard cases above.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

* test(mutation): register openrouter-free-model-credits-exhausted in stryker tap.testFiles

The new unit test covers src/sse/services/auth.ts, which is one of the 31
stryker-mutated modules — per check-mutation-test-coverage every covering
test must be listed in tap.testFiles or its mutant kills stop counting.
Registered the file so the blocking mutation-test-coverage gate passes.

Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>

---------

Co-authored-by: killmonger2317-coder <282069920+killmonger2317-coder@users.noreply.github.com>
Co-authored-by: diegosouzapw <8016841+diegosouzapw@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants