From b0cce952860b9ff51a0f731fbb8a7649ead23530 Mon Sep 17 00:00:00 2001 From: Bryan Morgan Date: Wed, 9 Jul 2025 10:18:15 -0400 Subject: Improve quota- and resource-related 429 error handling, also taking Code Assist customer tiers into consideration (#3609) --- packages/core/src/utils/quotaErrorDetection.ts | 82 ++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 packages/core/src/utils/quotaErrorDetection.ts (limited to 'packages/core/src/utils/quotaErrorDetection.ts') diff --git a/packages/core/src/utils/quotaErrorDetection.ts b/packages/core/src/utils/quotaErrorDetection.ts new file mode 100644 index 00000000..ec77f5ee --- /dev/null +++ b/packages/core/src/utils/quotaErrorDetection.ts @@ -0,0 +1,82 @@ +/** + * @license + * Copyright 2025 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +export interface ApiError { + error: { + code: number; + message: string; + status: string; + details: unknown[]; + }; +} + +interface StructuredError { + message: string; + status?: number; +} + +export function isApiError(error: unknown): error is ApiError { + return ( + typeof error === 'object' && + error !== null && + 'error' in error && + typeof (error as ApiError).error === 'object' && + 'message' in (error as ApiError).error + ); +} + +export function isStructuredError(error: unknown): error is StructuredError { + return ( + typeof error === 'object' && + error !== null && + 'message' in error && + typeof (error as StructuredError).message === 'string' + ); +} + +export function isProQuotaExceededError(error: unknown): boolean { + // Check for Pro quota exceeded errors by looking for the specific pattern + // This will match patterns like: + // - "Quota exceeded for quota metric 'Gemini 2.5 Pro Requests'" + // - "Quota exceeded for quota metric 'Gemini 1.5-preview Pro Requests'" + // - "Quota exceeded for quota metric 'Gemini beta-3.0 Pro Requests'" + // - "Quota exceeded for quota metric 'Gemini experimental-v2 Pro Requests'" + // We use string methods instead of regex to avoid ReDoS vulnerabilities + + const checkMessage = (message: string): boolean => + message.includes("Quota exceeded for quota metric 'Gemini") && + message.includes("Pro Requests'"); + + if (typeof error === 'string') { + return checkMessage(error); + } + + if (isStructuredError(error)) { + return checkMessage(error.message); + } + + if (isApiError(error)) { + return checkMessage(error.error.message); + } + + return false; +} + +export function isGenericQuotaExceededError(error: unknown): boolean { + if (typeof error === 'string') { + return error.includes('Quota exceeded for quota metric'); + } + + if (isStructuredError(error)) { + return error.message.includes('Quota exceeded for quota metric'); + } + + if (isApiError(error)) { + return error.error.message.includes('Quota exceeded for quota metric'); + } + + return false; +} -- cgit v1.2.3