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) */