diff --git a/packages/core/src/utils/errorParsing.test.ts b/packages/core/src/utils/errorParsing.test.ts index 291145d2e8b..b84259e8e45 100644 --- a/packages/core/src/utils/errorParsing.test.ts +++ b/packages/core/src/utils/errorParsing.test.ts @@ -114,4 +114,20 @@ describe('parseAndFormatApiError', () => { const expected = '[API Error: An unknown error occurred.]'; expect(parseAndFormatApiError(error)).toBe(expected); }); + + it('should decode and format a byte-array encoded error message', () => { + const json = JSON.stringify({ + error: { + code: 429, + message: 'No capacity available', + status: 'RESOURCE_EXHAUSTED', + }, + }); + const byteString = Array.from(json) + .map((c) => c.charCodeAt(0)) + .join(','); + const result = parseAndFormatApiError(byteString); + expect(result).toContain('[API Error: No capacity available'); + expect(result).toContain('RESOURCE_EXHAUSTED'); + }); }); diff --git a/packages/core/src/utils/errorParsing.ts b/packages/core/src/utils/errorParsing.ts index bad61ea9e24..64c7c6c285f 100644 --- a/packages/core/src/utils/errorParsing.ts +++ b/packages/core/src/utils/errorParsing.ts @@ -9,6 +9,18 @@ import { DEFAULT_GEMINI_FLASH_MODEL } from '../config/models.js'; import type { UserTierId } from '../code_assist/types.js'; import { AuthType } from '../core/contentGenerator.js'; +function tryDecodeByteArray(s: string): string | null { + if (!/^\d+(,\d+)+$/.test(s)) { + return null; + } + try { + const bytes = new Uint8Array(s.split(',').map(Number)); + return new TextDecoder().decode(bytes); + } catch { + return null; + } +} + const RATE_LIMIT_ERROR_MESSAGE_USE_GEMINI = '\nPlease wait and try again later. To increase your limits, request a quota increase through AI Studio, or switch to another /auth method'; const RATE_LIMIT_ERROR_MESSAGE_VERTEX = @@ -40,6 +52,16 @@ export function parseAndFormatApiError( fallbackModel?: string, ): string { if (isStructuredError(error)) { + const decoded = tryDecodeByteArray(error.message); + if (decoded) { + return parseAndFormatApiError( + decoded, + authType, + userTier, + currentModel, + fallbackModel, + ); + } let text = `[API Error: ${error.message}]`; if (error.status === 429) { text += getRateLimitMessage(authType, fallbackModel); @@ -49,9 +71,19 @@ export function parseAndFormatApiError( // The error message might be a string containing a JSON object. if (typeof error === 'string') { + const decoded = tryDecodeByteArray(error); + if (decoded) { + return parseAndFormatApiError( + decoded, + authType, + userTier, + currentModel, + fallbackModel, + ); + } const jsonStart = error.indexOf('{'); if (jsonStart === -1) { - return `[API Error: ${error}]`; // Not a JSON error, return as is. + return `[API Error: ${error}]`; } const jsonString = error.substring(jsonStart);