From 10b39a1981cf0a41bca1d4a0dfb6c20d68afb167 Mon Sep 17 00:00:00 2001 From: Jenny Bryan Date: Fri, 29 Aug 2025 19:05:54 -0700 Subject: [PATCH] Account for curly braces in Google-provided error message Fixes https://github.com/tidyverse/googlesheets4/issues/319 --- NEWS.md | 7 ++++-- R/response_process.R | 22 ++++++++++++++---- tests/testthat/_snaps/response_process.md | 9 +++---- ...heets-get-quota-exceeded-readgroup_429.rds | Bin 1471 -> 1519 bytes 4 files changed, 28 insertions(+), 10 deletions(-) diff --git a/NEWS.md b/NEWS.md index 1e689dc1..ed0b1fe8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,7 +1,10 @@ # gargle (development version) -* Fixed a bug when displaying a request failure that includes a localized - message in the error details (#293). +* Fixed some bugs around surfacing the details of a request failure: + - Better handling when the error details include a localized message (#293) + - Defensive escaping of `{..}` in Google-provided error messages, to prevent + `cli::cli_abort()` from trying (and failing) to do string interpolation + (https://github.com/tidyverse/googlesheets4/issues/319) * gargle is better able to detect when it's running on Posit Workbench, but not necessarily in RStudio, such as in Positron or VS Code (#291). diff --git a/R/response_process.R b/R/response_process.R index d0bf8dce..368e5ad9 100644 --- a/R/response_process.R +++ b/R/response_process.R @@ -165,7 +165,7 @@ gargle_error_message <- function(resp, call = caller_env()) { "*" = content$error, "*" = content$error_description ) - return(message) + return(escape_braces(message)) } if (is.null(error)) { @@ -174,7 +174,7 @@ gargle_error_message <- function(resp, call = caller_env()) { httr::http_status(resp)$message, "*" = content$error_description ) - return(message) + return(escape_braces(message)) } errors <- error[["errors"]] @@ -190,7 +190,7 @@ gargle_error_message <- function(resp, call = caller_env()) { error_details <- error$details if (is.null(error_details)) { - return(message) + return(escape_braces(message)) } # https://github.com/googleapis/googleapis/blob/master/google/rpc/error_details.proto @@ -219,7 +219,7 @@ gargle_error_message <- function(resp, call = caller_env()) { "", reveal_details(error_details) ) - return(message) + return(escape_braces(message)) } # developed from @@ -371,3 +371,17 @@ gargle_html_error_message <- function(resp) { ) ) } + +# Google APIs might return error messages containing curly braces, e.g. +# "metadata.quota_unit: 1/min/{project}/{user}" +# This can cause problems when eventually process by cli::cli_abort(), e.g. +# Error: +# ! ! Could not evaluate cli `{}` expression: `project`. +# Caused by error in `eval(expr, envir = envir)`: +# ! object 'project' not found +# So we need to escape them by doubling them, so they are taken literally. +# Seen by me and by a user: +# https://github.com/tidyverse/googlesheets4/issues/319 +escape_braces <- function(msg) { + gsub("([{}])", "\\1\\1", msg) +} diff --git a/tests/testthat/_snaps/response_process.md b/tests/testthat/_snaps/response_process.md index c0df8696..e591b253 100644 --- a/tests/testthat/_snaps/response_process.md +++ b/tests/testthat/_snaps/response_process.md @@ -11,15 +11,16 @@ Error details: * reason: RATE_LIMIT_EXCEEDED * domain: googleapis.com + * metadata.quota_limit_value: 60 + * metadata.service: sheets.googleapis.com + * metadata.consumer: projects/603366585132 + * metadata.quota_unit: 1/min/{project}/{user} * metadata.quota_location: global * metadata.quota_metric: sheets.googleapis.com/read_requests * metadata.quota_limit: ReadRequestsPerMinutePerUser - * metadata.quota_limit_value: 60 - * metadata.consumer: projects/603366585132 - * metadata.service: sheets.googleapis.com Links * Description: Request a higher quota limit. - URL: https://cloud.google.com/docs/quota#requesting_higher_quota + URL: https://cloud.google.com/docs/quotas/help/request_increase # Request for non-existent resource (Drive) diff --git a/tests/testthat/fixtures/sheets-spreadsheets-get-quota-exceeded-readgroup_429.rds b/tests/testthat/fixtures/sheets-spreadsheets-get-quota-exceeded-readgroup_429.rds index 1196cafc42a594bbfc0f8298fded8c905ebc27c1..73bd39fa05e7758e0e422a22df847db499ee76e1 100644 GIT binary patch literal 1519 zcmV)1&SqxTk(}~{D+ewV7k)!-aN)wQ;KC2!%z<;DXLm)BW`~J*~rRCX*S@Oisb~1iVgMfv;KkT!znBW-@sHz9*$8HVi}b2$7=LWvpux z>`_rPnPZ$R8^YrRTj8`(e%!iu^n@LhUD10s=sWk#^4T8{;F@KZUcl<)8K`=V4{ z+pRp^>QG`^Vl%ct-MV&62AkFTDQ*sKA3c@THPI;#2K%?yTkY-TCxXY45>Lp|!G_lO1r4p+8T~sMmR#2(30sqS-w6oVrC{NUycN3zqQbLez zR`+WAjrvagK{5!J372*{330Kvw3*vjUS7)GL=N7ptgKf`rBc4PRH&?{OeC!5?MlJH zF76Vmu$tV^?D_67u^{sCn0U&?4iS;=g2v_q^T9v7&zsDZ#FYg(@JJ-PtYySCnMK{M zwzII*I@5yi6G&cU(J%CcD0rMnVyetV@^|}%4hPQ)%u`YkiQn%R;@c)>XRs{`;>3)G z@AV6S2Pe;cB4okCvZp5`$F2Ylo%@*p#k8@|po~YtIqC}H3M%P|j%CuOLc;Ske6EBX zA6L(bQO=LDdbia&Fv`X9+q3Y7oQ1JJ-_l>;2ZE_hB{3ZJPi&K&GF>xZV)+Xq8^BohmbI6R{*EaqUUJ)G>=c$l>q zWRNw}=Ng18>3fvpSiUAz71hP#1lvAIRFqlHUKDkyT}TONcuIgPxELfqisCA0-gucs zC`UMFJhy?=0EUn|0;A>1dOj4u>H_!X>M)L;2O@_^PEEAffK;G} z9AXh+*FrXRs7%Ztk8tEr*Ow%C^?|;Nh;@*nF*ONVOzk)pgB^jZ!gs)G5eR++1aG^( z^NjF~)zZ?^>gvkcN_nZWSj|^m!ma z5g5VbEp;fAy?Q2lpm12^o>{CZ9P4g}MXLtJ(A_|t40f-!YVG^=y?P7w->%i}47U$m z2neGTM|X(p0LoY;a+s`09^{}M0NoB~qLx`L#Y`0rA+%~L72Hv64YE>?U=~Ik;8FF^ z1K*`m8I%pkt?@FlJ2PIY{GO#**etwFg1Bw=4BKg1A-gX0+)yoKTXQRQ8wE{}1kh|m ziU)-61r&srN8n&?Xm=L9o#p>O8+M89#dBv<_c%_l(PbkR3X@Y$;}Q9ZFzV56kLaTo z#8MoI5^Q~LD;wRgn>O>U$h*KZixXZDx%AVk z-?o0d`pxavUp-7z9iR;_Pya1&Rq9gVGe$s=xZ$!EkHftG9jFj z0IZ$3fJOtVC7YW!`^VLIJdvej-^zFk1%m6wb&c;QjoO{+HWb=V6B*Gf zPghNocpC17sxNzt)6?)03@@tJvF8%D-#~!mZ(V!3{`=UrMB!!+FZSt}hkZ((NOmwKz z%$J@oFX$&`qVkdA*X-XtnG5gWwrVZXotwk9-5wReQDn!I#D+nOn$rAEN$Q;I4LwVB V97=%jAnu?I`U`;J+sOqH007YL_qqT8 literal 1471 zcmV;w1wi^AiwFP!000001MOE|ZyQArcWlR|PE%S{s(3+NjD(@Y|C6Y338~e(Nvfs^ zwo_6eWNq)(zHRPque*D$lag=27l0R@5JKXi--9RK;Y)y2*uA?w-yIk6=K)?C>9V`C zv$Hevo1GaSl`@%3Hj~e0GufP&=B|o=l6F~q3z>Z8f*6Uxxx+g3Ix`UBtTrKJVj}2Z zR?~=8pRU%KLlM;d?RxXk@cz?J$wAX*#*>qo^dgduesYSP1nunsr_})4d&2~C zt~a=s)XbrH3OP!U7a9pdY0%y4?e}-LcONDt*o4`5JWh~nMtif|SzT?HZvhK#w$?UU zjYea|XjfYsDH}X-{Gvu|j%;4#Ck_f|mlX}! z8qu*mQRj5&j{s(d=v3h5ua-5a8K^4HQDQ1Fv+9hoszV7!nnW_7zd5UpsZh5{97$yX z`P!@+)g`f8geI@DsTM4+a0+cELT9dH!XcUonQ}-rATD8>A)8^2r^=4Ji5VB;EAd_R zLpv+STs+j{!MrmZ9@Lw)=IbZ$|386+-(N?4R{7xX1$xYFxzIEYxf@<@O2G_J1qmg*%Y1jQ6CsuMb~AXXaY$0iIBb09b7 zh-ofWPAH+7gDH%_l9!27<%}sbU6e>97btmNQ`vPn#h~yNh&X{Y597d!w*+V5MG1g1 zqLk2b2grq33haD&CDEB$;c8Qxy@%PemM$ zY}a~%XlK3AZm+Me-CS$7Ta{WlP~Q(7seQjU*gx#w>5Y0vJKe*vgWbK|p}7A}uXi`R z-dDj37|9sFA<84X3?+~uSOML`U}O?MA$u}R@&uZZvmuv{l;lZo%Va|}QaGgv@bL5u z5}f^j@c_|14^A;T6d;~^aO8!tJigwDGbvc*UH~ksM}G!ZoT~Zn;(AJf00PC1=X}r zq+^OgjY={TnuHv?PFRhJZO<8&#Lop)rBs;|>4EYDaghrTnu&T6H>j6vQU3d1JJ~2W zjbul*0yvuS`phy{Ky=R|+^FABKKrQOyW71Za^c4bFDuD~uBIVJxp2Aba)VHO>eng1 zmb{AerCuc6&V+waA5|uh3a5zfbhXw1?{6PG?DPlR)iJpRJ^;dj)Z1DMitB>^rFH}t zrMpM*M&N=hBcf8-JnRev(*&u)9V>`YyFHB03;T=DDdtGzO^bvr+9jVhc5Q9$hV({2 zVfMLnX%;MV4OMnbPGha%|1{l%auF Zl%A=kh;+dm;Z)C#KLC%^3D&|8000jb)ye<>