@@ -325,7 +325,7 @@ describe('classifyGoogleError', () => {
325325 expect ( result ) . toBeInstanceOf ( TerminalQuotaError ) ;
326326 } ) ;
327327
328- it ( 'should return original error for 429 without specific details ' , ( ) => {
328+ it ( 'should return RetryableQuotaError for any 429 ' , ( ) => {
329329 const apiError : GoogleApiError = {
330330 code : 429 ,
331331 message : 'Too many requests' ,
@@ -340,7 +340,10 @@ describe('classifyGoogleError', () => {
340340 vi . spyOn ( errorParser , 'parseGoogleApiError' ) . mockReturnValue ( apiError ) ;
341341 const originalError = new Error ( ) ;
342342 const result = classifyGoogleError ( originalError ) ;
343- expect ( result ) . toBe ( originalError ) ;
343+ expect ( result ) . toBeInstanceOf ( RetryableQuotaError ) ;
344+ if ( result instanceof RetryableQuotaError ) {
345+ expect ( result . retryDelayMs ) . toBe ( 5000 ) ;
346+ }
344347 } ) ;
345348
346349 it ( 'should classify nested JSON string 404 error as ModelNotFoundError' , ( ) => {
@@ -389,4 +392,61 @@ describe('classifyGoogleError', () => {
389392 } ) ;
390393 }
391394 } ) ;
395+
396+ it ( 'should return RetryableQuotaError with 5s fallback for generic 429 without specific message' , ( ) => {
397+ const generic429 = {
398+ status : 429 ,
399+ message : 'Resource exhausted. No specific retry info.' ,
400+ } ;
401+
402+ const result = classifyGoogleError ( generic429 ) ;
403+
404+ expect ( result ) . toBeInstanceOf ( RetryableQuotaError ) ;
405+ if ( result instanceof RetryableQuotaError ) {
406+ expect ( result . retryDelayMs ) . toBe ( 5000 ) ;
407+ }
408+ } ) ;
409+
410+ it ( 'should return RetryableQuotaError with 5s fallback for 429 with empty details and no regex match' , ( ) => {
411+ const errorWithEmptyDetails = {
412+ error : {
413+ code : 429 ,
414+ message : 'A generic 429 error with no retry message.' ,
415+ details : [ ] ,
416+ } ,
417+ } ;
418+
419+ const result = classifyGoogleError ( errorWithEmptyDetails ) ;
420+
421+ expect ( result ) . toBeInstanceOf ( RetryableQuotaError ) ;
422+ if ( result instanceof RetryableQuotaError ) {
423+ expect ( result . retryDelayMs ) . toBe ( 5000 ) ;
424+ }
425+ } ) ;
426+
427+ it ( 'should return RetryableQuotaError with 5s fallback for 429 with some detail' , ( ) => {
428+ const errorWithEmptyDetails = {
429+ error : {
430+ code : 429 ,
431+ message : 'A generic 429 error with no retry message.' ,
432+ details : [
433+ {
434+ '@type' : 'type.googleapis.com/google.rpc.ErrorInfo' ,
435+ reason : 'QUOTA_EXCEEDED' ,
436+ domain : 'googleapis.com' ,
437+ metadata : {
438+ quota_limit : '' ,
439+ } ,
440+ } ,
441+ ] ,
442+ } ,
443+ } ;
444+
445+ const result = classifyGoogleError ( errorWithEmptyDetails ) ;
446+
447+ expect ( result ) . toBeInstanceOf ( RetryableQuotaError ) ;
448+ if ( result instanceof RetryableQuotaError ) {
449+ expect ( result . retryDelayMs ) . toBe ( 5000 ) ;
450+ }
451+ } ) ;
392452} ) ;
0 commit comments