From 6064dd0f62de90b89e716f4dd71124a7a415c693 Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Thu, 4 Dec 2025 15:19:54 -0600 Subject: [PATCH 1/3] Only attempt to close responses Fixes #817 --- NEWS.md | 1 + R/req-perform-connection.R | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NEWS.md b/NEWS.md index 9541d84b..3470d1d1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,6 @@ # httr2 (development version) +* `req_perform_connection()` no longer errors with `no applicable method for 'close' applied to an object of class "c('httr2_failure', 'httr2_error', 'rlang_error', 'error', 'condition')` (#817). * Refactor `url_modify()` to better retain exact formatting of URL components that are not modified. (#788, #794) diff --git a/R/req-perform-connection.R b/R/req-perform-connection.R index 3dbfb664..4923d65a 100644 --- a/R/req-perform-connection.R +++ b/R/req-perform-connection.R @@ -81,7 +81,7 @@ req_perform_connection <- function( retry_check_breaker(req, tries) sys_sleep(delay, "for retry backoff") - if (!is.null(resp)) { + if (is_response(resp)) { close(resp) } resp <- req_perform_connection1(req, handle, blocking = blocking) From d9b65306bf1650e35a0b9341ff79cd38559653df Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Thu, 4 Dec 2025 15:29:57 -0600 Subject: [PATCH 2/3] Test + refactor --- R/req-error.R | 2 +- R/req-perform-connection.R | 7 ++----- tests/testthat/_snaps/req-perform-connection.md | 10 ++++++++++ tests/testthat/test-req-perform-connection.R | 9 +++++++++ 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/R/req-error.R b/R/req-error.R index 9387fd96..c76715a2 100644 --- a/R/req-error.R +++ b/R/req-error.R @@ -112,7 +112,7 @@ error_body <- function(req, resp, call = caller_env()) { } capture_curl_error <- function(code, call = caller_env()) { - resp <- tryCatch( + tryCatch( code, error = function(err) curl_cnd(err, call = call) ) diff --git a/R/req-perform-connection.R b/R/req-perform-connection.R index 4923d65a..7b0e3817 100644 --- a/R/req-perform-connection.R +++ b/R/req-perform-connection.R @@ -143,14 +143,11 @@ req_perform_connection1 <- function(req, handle, blocking = TRUE) { err <- capture_curl_error({ conn <- curl::curl(req$url, handle = handle) # Must open the stream in order to initiate the connection - withCallingHandlers( - open(conn, "rbf", blocking = blocking), - warning = \(cnd) tryInvokeRestart("muffleWarning"), - error = \(cnd) close(conn) - ) + suppressWarnings(open(conn, "rbf", blocking = blocking)) body <- StreamingBody$new(conn) }) if (is_error(err)) { + close(conn) return(err) } diff --git a/tests/testthat/_snaps/req-perform-connection.md b/tests/testthat/_snaps/req-perform-connection.md index e9050317..79eca5cd 100644 --- a/tests/testthat/_snaps/req-perform-connection.md +++ b/tests/testthat/_snaps/req-perform-connection.md @@ -21,6 +21,16 @@ Caused by error in `open()`: ! Failed to connect +# correclty reports curl error with retries (#817) + + Code + req_perform_connection(req) + Condition + Error in `req_perform_connection()`: + ! Failed to perform HTTP request. + Caused by error in `open()`: + ! Failed to connect + # validates its input Code diff --git a/tests/testthat/test-req-perform-connection.R b/tests/testthat/test-req-perform-connection.R index 3f75ad73..0e9c45db 100644 --- a/tests/testthat/test-req-perform-connection.R +++ b/tests/testthat/test-req-perform-connection.R @@ -70,6 +70,15 @@ test_that("curl errors become errors", { expect_null(last_response()) }) +test_that("correclty reports curl error with retries (#817)", { + local_mocked_bindings(open = function(...) abort("Failed to connect")) + + req <- request("http://127.0.0.1") |> + req_retry(max_tries = 2, retry_on_failure = TRUE, backoff = \(i) 0) + + expect_snapshot(req_perform_connection(req), error = TRUE) +}) + test_that("mocking works", { req_200 <- request("https://ok") req_404 <- request("https://notok") From 3d6b27409316cfb9234fb4adce3bee24c024696a Mon Sep 17 00:00:00 2001 From: Hadley Wickham Date: Thu, 4 Dec 2025 15:38:37 -0600 Subject: [PATCH 3/3] Clarify return type --- R/req-error.R | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/R/req-error.R b/R/req-error.R index c76715a2..9a8e4179 100644 --- a/R/req-error.R +++ b/R/req-error.R @@ -113,7 +113,10 @@ error_body <- function(req, resp, call = caller_env()) { capture_curl_error <- function(code, call = caller_env()) { tryCatch( - code, + { + code + NULL + }, error = function(err) curl_cnd(err, call = call) ) }