@@ -445,4 +445,113 @@ describe('parseGoogleApiError', () => {
445445 expect ( parsed ?. code ) . toBe ( 429 ) ;
446446 expect ( parsed ?. message ) . toBe ( 'Quota exceeded' ) ;
447447 } ) ;
448+
449+ it ( 'should parse an error wrapped inside cause.message by gaxios' , ( ) => {
450+ const mockError = {
451+ code : 429 ,
452+ status : 429 ,
453+ cause : {
454+ message : JSON . stringify ( [
455+ {
456+ error : {
457+ code : 429 ,
458+ message :
459+ 'No capacity available for model gemini-3.1-pro-preview on the server' ,
460+ details : [
461+ {
462+ '@type' : 'type.googleapis.com/google.rpc.ErrorInfo' ,
463+ reason : 'MODEL_CAPACITY_EXHAUSTED' ,
464+ domain : 'cloudcode-pa.googleapis.com' ,
465+ metadata : { model : 'gemini-3.1-pro-preview' } ,
466+ } ,
467+ ] ,
468+ } ,
469+ } ,
470+ ] ) ,
471+ code : 429 ,
472+ status : 'Too Many Requests' ,
473+ } ,
474+ } ;
475+
476+ const parsed = parseGoogleApiError ( mockError ) ;
477+ expect ( parsed ) . not . toBeNull ( ) ;
478+ expect ( parsed ?. code ) . toBe ( 429 ) ;
479+ expect ( parsed ?. message ) . toBe (
480+ 'No capacity available for model gemini-3.1-pro-preview on the server' ,
481+ ) ;
482+ expect ( parsed ?. details ) . toHaveLength ( 1 ) ;
483+ expect ( parsed ?. details [ 0 ] [ '@type' ] ) . toBe (
484+ 'type.googleapis.com/google.rpc.ErrorInfo' ,
485+ ) ;
486+ } ) ;
487+
488+ it ( 'should parse an error where cause is a plain ErrorShape and propagate outer code' , ( ) => {
489+ const mockError = {
490+ code : 429 ,
491+ cause : {
492+ message : 'Quota exceeded on the server' ,
493+ } ,
494+ } ;
495+
496+ const parsed = parseGoogleApiError ( mockError ) ;
497+ expect ( parsed ) . not . toBeNull ( ) ;
498+ expect ( parsed ?. code ) . toBe ( 429 ) ;
499+ expect ( parsed ?. message ) . toBe ( 'Quota exceeded on the server' ) ;
500+ } ) ;
501+
502+ it ( 'should parse an error where cause is a standard Error object and propagate outer status' , ( ) => {
503+ const mockError = {
504+ status : 503 ,
505+ cause : new Error ( 'Service Unavailable' ) ,
506+ } ;
507+
508+ const parsed = parseGoogleApiError ( mockError ) ;
509+ expect ( parsed ) . not . toBeNull ( ) ;
510+ expect ( parsed ?. code ) . toBe ( 503 ) ;
511+ expect ( parsed ?. message ) . toBe ( 'Service Unavailable' ) ;
512+ } ) ;
513+
514+ it ( 'should defensively parse numeric string status codes from outer error' , ( ) => {
515+ const mockError = {
516+ status : '503' ,
517+ cause : new Error ( 'Service Unavailable' ) ,
518+ } ;
519+
520+ const parsed = parseGoogleApiError ( mockError ) ;
521+ expect ( parsed ) . not . toBeNull ( ) ;
522+ expect ( parsed ?. code ) . toBe ( 503 ) ;
523+ expect ( parsed ?. message ) . toBe ( 'Service Unavailable' ) ;
524+ } ) ;
525+
526+ it ( 'should return null for non-numeric string status codes from outer error' , ( ) => {
527+ const mockError = {
528+ status : 'Too Many Requests' ,
529+ cause : new Error ( 'Quota exceeded' ) ,
530+ } ;
531+
532+ const parsed = parseGoogleApiError ( mockError ) ;
533+ expect ( parsed ) . toBeNull ( ) ;
534+ } ) ;
535+
536+ it ( 'should return null for empty or whitespace-only string status codes from outer error' , ( ) => {
537+ const mockError = {
538+ status : ' ' ,
539+ cause : new Error ( 'Quota exceeded' ) ,
540+ } ;
541+
542+ const parsed = parseGoogleApiError ( mockError ) ;
543+ expect ( parsed ) . toBeNull ( ) ;
544+ } ) ;
545+
546+ it ( 'should parse an error where cause is a plain string and propagate outer status' , ( ) => {
547+ const mockError = {
548+ status : 429 ,
549+ cause : 'Quota exceeded on the server' ,
550+ } ;
551+
552+ const parsed = parseGoogleApiError ( mockError ) ;
553+ expect ( parsed ) . not . toBeNull ( ) ;
554+ expect ( parsed ?. code ) . toBe ( 429 ) ;
555+ expect ( parsed ?. message ) . toBe ( 'Quota exceeded on the server' ) ;
556+ } ) ;
448557} ) ;
0 commit comments