Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

.destfile unexpectedly written even on error #178

Closed
arcresu opened this issue Feb 23, 2023 · 5 comments
Closed

.destfile unexpectedly written even on error #178

arcresu opened this issue Feb 23, 2023 · 5 comments
Labels
bug an unexpected problem or unintended behavior

Comments

@arcresu
Copy link

arcresu commented Feb 23, 2023

When .destfile is provided, gh will write to it even if the API returned an error:

library(gh)

# trying to download a file from a github repo that unexpectedly doesn't exist
> gh("/repos/r-lib/gh/contents/DOES_NOT_EXIST", .destfile="gh_destfile", .accept = "application/vnd.github.v3.raw")
Error in `gh_process_response()`:
! GitHub API error (404): Not FoundURL not found:
  <https://api.github.com/repos/r-lib/gh/contents/DOES_NOT_EXIST>Read more at
  <https://docs.github.com/rest/reference/repos#get-repository-content>

> readLines(file("gh_destfile"), warn=FALSE)
[1] "{\"message\":\"Not Found\",\"documentation_url\":\"https://docs.github.com/rest/reference/repos#get-repository-content\"}

In the absence of .destfile, when the request succeeds (e.g. change DOES_NOT_EXIST to README.md), the contents of the file are printed out. When it fails there's an error message, but nothing else is printed. However when .destfile is given, that file is written to whether or not the request succeeded. In the error case, the JSON-encoded error is put in the file even when .accept specified that we were expecting to write something other than JSON.

It's a bit of a surprising behaviour, and it's the underlying cause of a bug in usethis (r-lib/usethis#1774). Granted, usethis could have been handling the error more carefully.

I think it would be less surprising if the .destfile were only created and written when the API request succeeded. All data from the API error already appears in the R error, so we don't lose any information.

@gaborcsardi
Copy link
Member

What version of gh did you use?

@arcresu
Copy link
Author

arcresu commented Feb 23, 2023

I get the same behaviour on both 1.4.0 from CRAN and the latest git HEAD.

The relevant code I think is:

gh/R/gh.R

Lines 286 to 289 in 26c50f3

resp <- httr2::req_perform(req, path = x$dest)
if (httr2::resp_status(resp) >= 300) {
gh_error(resp, error_call = error_call)
}

It writes the request to the output file first and only checks the response status afterwards.

@gaborcsardi gaborcsardi added the bug an unexpected problem or unintended behavior label Feb 23, 2023
@jennybc
Copy link
Member

jennybc commented Feb 23, 2023

I went further back in time, i.e. to gh v1.3.1 and v1.3.0, and the behaviour was the same (.destfile is written even on error). So I don't think this is from the httr2 refactoring.

cderv added a commit to cderv/pandoc that referenced this issue Feb 26, 2024
@gaborcsardi
Copy link
Member

I guess this is a side effect of how HTTP works. Even if the status code is an error, the response has a body, and the HTTP client that handles .destfile will write it out.

So I guess we should delete it on error?

That can also lead some weird consequences, e.g. if you want to overwrite a file, and there is an error, then it will be deleted.

@gaborcsardi
Copy link
Member

We could write the response to a temporary file and then rename it on success and delete it on failure.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug an unexpected problem or unintended behavior
Projects
None yet
Development

No branches or pull requests

3 participants