Improve quota- and resource-related 429 error handling, also taking Code Assist customer tiers into consideration (#3609)

This commit is contained in:
Bryan Morgan
2025-07-09 10:18:15 -04:00
committed by GitHub
parent 8f2da86aa5
commit b0cce95286
14 changed files with 611 additions and 63 deletions

View File

@@ -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;
}