Skip to content

Commit e4458b8

Browse files
stefandevoclaude
andcommitted
fix(codex): prevent infinite loop when fetching models on settings screen
When Codex is not connected/authenticated, the /api/codex/models endpoint returns 503. The fetchCodexModels function had no cooldown after failures, causing infinite retries when navigating to the Settings screen. Added codexModelsLastFailedAt state to track failed fetch attempts and skip retries for 30 seconds after a failure. This prevents the infinite loop while still allowing periodic retry attempts. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent f3f5d05 commit e4458b8

1 file changed

Lines changed: 15 additions & 1 deletion

File tree

apps/ui/src/store/app-store.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,7 @@ export interface AppState {
689689
codexModelsLoading: boolean;
690690
codexModelsError: string | null;
691691
codexModelsLastFetched: number | null;
692+
codexModelsLastFailedAt: number | null;
692693

693694
// Pipeline Configuration (per-project, keyed by project path)
694695
pipelineConfigByProject: Record<string, PipelineConfig>;
@@ -1286,6 +1287,7 @@ const initialState: AppState = {
12861287
codexModelsLoading: false,
12871288
codexModelsError: null,
12881289
codexModelsLastFetched: null,
1290+
codexModelsLastFailedAt: null,
12891291
pipelineConfigByProject: {},
12901292
worktreePanelVisibleByProject: {},
12911293
showInitScriptIndicatorByProject: {},
@@ -3113,11 +3115,21 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
31133115

31143116
// Codex Models actions
31153117
fetchCodexModels: async (forceRefresh = false) => {
3116-
const { codexModelsLastFetched, codexModelsLoading } = get();
3118+
const { codexModelsLastFetched, codexModelsLoading, codexModelsLastFailedAt } = get();
31173119

31183120
// Skip if already loading
31193121
if (codexModelsLoading) return;
31203122

3123+
// Skip if recently failed (< 30 seconds ago) and not forcing refresh
3124+
const FAILURE_COOLDOWN = 30000; // 30 seconds
3125+
if (
3126+
!forceRefresh &&
3127+
codexModelsLastFailedAt &&
3128+
Date.now() - codexModelsLastFailedAt < FAILURE_COOLDOWN
3129+
) {
3130+
return;
3131+
}
3132+
31213133
// Skip if recently fetched (< 5 minutes ago) and not forcing refresh
31223134
if (!forceRefresh && codexModelsLastFetched && Date.now() - codexModelsLastFetched < 300000) {
31233135
return;
@@ -3142,12 +3154,14 @@ export const useAppStore = create<AppState & AppActions>()((set, get) => ({
31423154
codexModelsLastFetched: Date.now(),
31433155
codexModelsLoading: false,
31443156
codexModelsError: null,
3157+
codexModelsLastFailedAt: null, // Clear failure on success
31453158
});
31463159
} catch (error) {
31473160
const errorMessage = error instanceof Error ? error.message : 'Unknown error';
31483161
set({
31493162
codexModelsError: errorMessage,
31503163
codexModelsLoading: false,
3164+
codexModelsLastFailedAt: Date.now(), // Record failure time for cooldown
31513165
});
31523166
}
31533167
},

0 commit comments

Comments
 (0)