From 5a308db409392d88e637ee66b9c693b8b7557198 Mon Sep 17 00:00:00 2001 From: kaitranntt Date: Mon, 2 Feb 2026 11:42:02 -0500 Subject: [PATCH] fix(quota): improve 403 error messaging for forbidden accounts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of showing "Quota access forbidden" generic error, now shows: - Antigravity: "403 Forbidden - No Gemini Code Assist access" - Codex: "403 Forbidden - No quota API access" Keeps success=false with isForbidden flag so UI can show distinct "403" badge (similar to Antigravity-Manager) rather than conflating with 0% exhausted state. 403 ≠ 0% exhausted - they are semantically different: - 403: Account lacks API access entirely - 0%: Account has access but quota is used up (shows reset time) --- src/cliproxy/quota-fetcher-codex.ts | 5 ++++- src/cliproxy/quota-fetcher.ts | 4 +++- src/cliproxy/quota-types.ts | 2 ++ ui/src/lib/api-client.ts | 2 ++ 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/cliproxy/quota-fetcher-codex.ts b/src/cliproxy/quota-fetcher-codex.ts index 9343d436..878dbe2d 100644 --- a/src/cliproxy/quota-fetcher-codex.ts +++ b/src/cliproxy/quota-fetcher-codex.ts @@ -253,13 +253,16 @@ export async function fetchCodexQuota( } if (response.status === 403) { + // 403 = account lacks API access (not same as quota exhausted) + // Keep success=false with isForbidden flag for UI to show distinct "403" badge return { success: false, windows: [], planType: null, lastUpdated: Date.now(), - error: 'Quota access not available (free plan may not have quota API access)', + error: '403 Forbidden - No quota API access', accountId, + isForbidden: true, }; } diff --git a/src/cliproxy/quota-fetcher.ts b/src/cliproxy/quota-fetcher.ts index 41203461..a2c79d41 100644 --- a/src/cliproxy/quota-fetcher.ts +++ b/src/cliproxy/quota-fetcher.ts @@ -407,12 +407,14 @@ async function fetchAvailableModels(accessToken: string, _projectId: string): Pr clearTimeout(timeoutId); if (response.status === 403) { + // 403 = account lacks Gemini Code Assist access (not same as quota exhausted) + // Keep success=false with isForbidden flag for UI to show distinct "403" badge return { success: false, models: [], lastUpdated: Date.now(), isForbidden: true, - error: 'Quota access forbidden for this account', + error: '403 Forbidden - No Gemini Code Assist access', }; } diff --git a/src/cliproxy/quota-types.ts b/src/cliproxy/quota-types.ts index ae0ac8d3..f8759bbe 100644 --- a/src/cliproxy/quota-types.ts +++ b/src/cliproxy/quota-types.ts @@ -45,6 +45,8 @@ export interface CodexQuotaResult { accountId?: string; /** True if token is expired and needs re-authentication */ needsReauth?: boolean; + /** True if account lacks quota access (403) - displayed as 0% instead of error */ + isForbidden?: boolean; } /** diff --git a/ui/src/lib/api-client.ts b/ui/src/lib/api-client.ts index 51907b8a..a8d2bb87 100644 --- a/ui/src/lib/api-client.ts +++ b/ui/src/lib/api-client.ts @@ -180,6 +180,8 @@ export interface CodexQuotaResult { needsReauth?: boolean; /** True if result was served from cache */ cached?: boolean; + /** True if account lacks quota access (403) - displayed as 0% instead of error */ + isForbidden?: boolean; } /** Gemini CLI bucket (grouped by model series) */