fix: include configured fallback chain when running non-primary model#25922
Closed
Taskle wants to merge 1 commit intoopenclaw:mainfrom
Closed
fix: include configured fallback chain when running non-primary model#25922Taskle wants to merge 1 commit intoopenclaw:mainfrom
Taskle wants to merge 1 commit intoopenclaw:mainfrom
Conversation
When a session runs a non-primary model (e.g. after failover), resolveFallbackCandidates() previously returned an empty fallback list. This meant only the configured primary was available as a fallback. If the primary provider was in cooldown and at candidate index >0 (not probe-eligible), all candidates would be exhausted with no recovery path — creating a dead end after failover. Now the full configured fallback chain is included regardless of whether the current model matches the configured primary, giving non-primary sessions the same resilience as primary sessions. Fixes openclaw#25912
Contributor
|
Reviewed and landed on What shipped:
Validation:
Thanks for the issue analysis and patch direction, @Taskle. |
Contributor
|
Landed on main in bf5a96a with scoped fallback-chain fix + regression coverage; closing in favor of landed commit. |
joshavant
pushed a commit
that referenced
this pull request
Feb 25, 2026
margulans
pushed a commit
to margulans/Neiron-AI-assistant
that referenced
this pull request
Feb 25, 2026
Jackson3195
pushed a commit
to Jackson3195/openclaw-with-a-personal-touch
that referenced
this pull request
Feb 25, 2026
brianleach
pushed a commit
to brianleach/openclaw
that referenced
this pull request
Feb 26, 2026
2 tasks
execute008
pushed a commit
to execute008/openclaw
that referenced
this pull request
Feb 27, 2026
r4jiv007
pushed a commit
to r4jiv007/openclaw
that referenced
this pull request
Feb 28, 2026
zooqueen
pushed a commit
to hanzoai/bot
that referenced
this pull request
Mar 6, 2026
thebenjaminlee
pushed a commit
to escape-velocity-ventures/openclaw
that referenced
this pull request
Mar 7, 2026
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.
Summary
When a session runs a non-primary model (e.g. after failover from Claude to Codex),
resolveFallbackCandidates()skips the configured fallback chain and only adds the configured primary as a fallback. If that primary's provider is still in cooldown and at candidate index >0 (not eligible for probing), all candidates are exhausted — creating a dead end with no recovery.Fixes #25912
Problem
In
src/agents/model-fallback.ts, this guard discards the entire fallback chain for non-primary models:This was intended for explicit
--modeloverrides, but it also fires when the session is running a failover model. The result:resolveFallbackCandidates()returns only Claude as a fallbackshouldProbePrimaryDuringCooldownreturnsfalseFix
Remove the early return and always include the configured fallback chain. The
createModelCandidateCollectoralready deduplicates by provider+model, so there's no risk of duplicate candidates. ThefallbacksOverridepath (for explicit spawn overrides) is preserved and takes priority.Before
Non-primary model fails → candidates:
[currentModel, configuredPrimary]After
Non-primary model fails → candidates:
[currentModel, ...configuredFallbacks, configuredPrimary]Changes
src/agents/model-fallback.ts: RemovesameModelCandidateguard andconfiguredPrimaryvariable (both now unused). Replace with comment explaining the design decision.src/agents/model-fallback.test.ts: Update 5 tests to reflect new behavior — override models now fall back through the configured chain instead of jumping straight to primary. RemovecreateOverrideFailureRunhelper (no longer needed). All 30 tests pass.Testing
Edge cases considered
[primary, ...fallbacks, primary(deduped)][override, ...fallbacks, primary]instead of[override, primary][fallback, ...otherFallbacks, primary]instead of[fallback, primary]fallbacksOverrideset (explicit spawn): unchanged — takes priority before this code pathenforceAllowlist: true, primary/override usefalseGreptile Summary
Removes early return that skipped the configured fallback chain when running non-primary models, fixing a dead-end scenario where sessions could fail to recover after failover. The fix ensures all models in the configured fallback chain remain reachable even when running override or failover models, while deduplication in
createModelCandidateCollectorprevents duplicate candidates.sameModelCandidatefunction andconfiguredPrimaryvariable (both became unnecessary after removing the guard)createOverrideFailureRuntest helper (no longer needed with updated test approach)Confidence Score: 5/5
Last reviewed commit: 61b9dcc