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

Failure to unzip when UNC path in use, leading to package installation failure in pak::pkg_install #745

Open
awong234 opened this issue Feb 28, 2025 · 6 comments

Comments

@awong234
Copy link

awong234 commented Feb 28, 2025

Error

I am encountering an error similar to #518 and #310. In these examples, the error was due to the user library path not being writeable. But I believe I am encountering a different issue.

Here are my session details:

R version 4.4.2 (2024-10-31 ucrt)
Platform: x86_64-w64-mingw32/x64
Running under: Windows 11 x64 (build 26100)

Matrix products: default


locale:
[1] LC_COLLATE=English_United States.utf8  LC_CTYPE=English_United States.utf8    LC_MONETARY=English_United States.utf8
[4] LC_NUMERIC=C                           LC_TIME=English_United States.utf8    

time zone: America/New_York
tzcode source: internal

attached base packages:
[1] stats     graphics  grDevices utils     datasets  methods   base     

loaded via a namespace (and not attached):
[1] compiler_4.4.2 tools_4.4.2 

Here is an example of the error:

path = tempdir()
path = gsub("C:", sprintf("//%s/C$", Sys.getenv("COMPUTERNAME")), path)
.libPaths(path)
.libPaths()
#> [1] "\\\\AW2024/C$/Users/AlecW/AppData/Local/Temp/RtmpgPK4Ui"
#> [2] "C:/Program Files/R/R-4.4.2/library"
install.packages("pak")
#> Installing package into '\\AW2024/C$/Users/AlecW/AppData/Local/Temp/RtmpgPK4Ui'
#> (as 'lib' is unspecified)
#> package 'pak' successfully unpacked and MD5 sums checked
#> 
#> The downloaded binary packages are in
#>  C:\Users\AlecW\AppData\Local\Temp\RtmpgPK4Ui\downloaded_packages
pak::pkg_install('fs')
#> ℹ Loading metadata database
#> ✔ Loading metadata database ... done
#>  
#> → Will install 1 package.
#> → Will download 1 CRAN package (413.43 kB).
#> + fs   1.6.5 [dl] (413.43 kB)
#> ℹ Getting 1 pkg (413.43 kB)
#> ✔ Cached copy of fs 1.6.5 (x86_64-w64-mingw32) is the latest build
#> Error: ! error in pak subprocess
#> Caused by error in `verify_extracted_package(filename, pkg_cache)`:
#> ! 
#> 'C:\Users\AlecW\AppData\Local\Temp\Rtmp6dheTX\file20e0342632ed/bin/windows/contrib/4.4/fs_1.6.5.zip'
#> is not a valid R package, it is an empty archive.

Created on 2025-02-27 with reprex v2.1.1

You might notice the strange handling in the second line; I am converting the path to use a UNC path, because I believe this to be the source of the error. In my particular case at work, we have network drives that are accessed commonly using UNC paths for greater consistency instead of letter drives, which can vary from user to user.

Expected behavior

Using the ordinary letter drive (in this case C:), we receive the ordinary outcome.

path = tempdir()
.libPaths(path)
.libPaths()
#> [1] "C:/Users/AlecW/AppData/Local/Temp/RtmpExT5JY"
#> [2] "C:/Program Files/R/R-4.4.2/library"
install.packages("pak")
#> Installing package into 'C:/Users/AlecW/AppData/Local/Temp/RtmpExT5JY'
#> (as 'lib' is unspecified)
#> package 'pak' successfully unpacked and MD5 sums checked
#> 
#> The downloaded binary packages are in
#>  C:\Users\AlecW\AppData\Local\Temp\RtmpExT5JY\downloaded_packages
pak::pkg_install('fs')
#> ℹ Loading metadata database
#> ✔ Loading metadata database ... done
#>  
#> → Will install 1 package.
#> → Will download 1 CRAN package (413.43 kB).
#> + fs   1.6.5 [dl] (413.43 kB)
#> ℹ Getting 1 pkg (413.43 kB)
#> ✔ Cached copy of fs 1.6.5 (x86_64-w64-mingw32) is the latest build
#> ✔ Installed fs 1.6.5  (74ms)
#> ✔ 1 pkg: added 1 [2.7s]

Created on 2025-02-27 with reprex v2.1.1

Problem details: pkgdepends and zip

I chose to post this issue in pak because there is precedent for the exact error message in other issues. But the underlying error is with zip, via pkgdepends.

Here is the full trace of the error:

<callr_error/rlib_error_3_0/rlib_error/error>
Error: 
! error in pak subprocess
Caused by error in `verify_extracted_package(filename, pkg_cache)`:
! C:\Users\AlecW\AppData\Local\Temp\Rtmp4GyF14\file76305a3a6e54/bin/windows/contrib/4.4/fs_1.6.5.zip is not a
valid R package, it is an empty archive.
---
Backtrace:
1. pak::pkg_install("fs")
2. pak:::remote(function(...) get("pkg_install_do_plan", asNamespace("pak"))(...), …
3. err$throw(res$error)
---
Subprocess backtrace:
 1. base::withCallingHandlers(cli_message = function(msg) { …
 2. get("pkg_install_do_plan", asNamespace("pak"))(...)
 3. proposal$install()
 4. pkgdepends::install_package_plan(plan, lib = private$library, num_workers = nw, …
 5. base::withCallingHandlers({ …
 6. pkgdepends:::handle_events(state, events)
 7. pkgdepends:::handle_event(state, i)
 8. proc$get_result()
 9. processx:::process_get_result(self, private)
10. private$post_process()
11. pkgdepends:::install_extracted_binary(filename, lib_cache, pkg_cache, lib, …
12. pkgdepends:::verify_extracted_package(filename, pkg_cache)
13. base::throw(pkg_error("{.path {filename}} is not a valid R package, it is an empty archive.", …
14. | base::signalCondition(cond)
15. global (function (e) …

I arrived at the source of the error by debugging through pkgdepends:::install_package_plan, start_task_install, make_install_process, make_unzip_process.

The unzip process actually fails silently, and it is not until verify_extracted_package(filename, pkg_cache) does an error raise, and only because the parent_path is empty (from verify_extracted_package)

But here is what we see when we run the unzip process manually, using either a regular path:

path = tempdir()
.libPaths(path)
install.packages('pkgdepends')
#> Installing package into 'C:/Users/AlecW/AppData/Local/Temp/RtmpYVDXaK'
#> (as 'lib' is unspecified)
#> also installing the dependencies 'callr', 'cli', 'curl', 'desc', 'filelock', 'jsonlite', 'lpSolve', 'pkgbuild', 'pkgcache', 'processx', 'ps', 'R6', 'zip'
#> package 'callr' successfully unpacked and MD5 sums checked
#> package 'cli' successfully unpacked and MD5 sums checked
#> package 'curl' successfully unpacked and MD5 sums checked
#> package 'desc' successfully unpacked and MD5 sums checked
#> package 'filelock' successfully unpacked and MD5 sums checked
#> package 'jsonlite' successfully unpacked and MD5 sums checked
#> package 'lpSolve' successfully unpacked and MD5 sums checked
#> package 'pkgbuild' successfully unpacked and MD5 sums checked
#> package 'pkgcache' successfully unpacked and MD5 sums checked
#> package 'processx' successfully unpacked and MD5 sums checked
#> package 'ps' successfully unpacked and MD5 sums checked
#> package 'R6' successfully unpacked and MD5 sums checked
#> package 'zip' successfully unpacked and MD5 sums checked
#> package 'pkgdepends' successfully unpacked and MD5 sums checked
#> 
#> The downloaded binary packages are in
#>  C:\Users\AlecW\AppData\Local\Temp\RtmpYVDXaK\downloaded_packages
library(pkgdepends)
prop = new_pkg_installation_proposal('fs', config = list(library = .libPaths()[[1L]]))
prop$download()
#> ℹ Loading metadata database
#> ✔ Loading metadata database ... done
#> ℹ Getting 1 pkg (413.43 kB)
#> ✔ Cached copy of fs 1.6.5 (x86_64-w64-mingw32) is the latest build
plan = prop$get_install_plan()
# Letter path succeeds
zip::unzip(zipfile = plan$file, exdir = path)
'fs' %in% dir(path)
#> [1] TRUE

Created on 2025-02-27 with reprex v2.1.1

... or a UNC path:

path = tempdir()
path = gsub("C:", sprintf("//%s/C$", Sys.getenv("COMPUTERNAME")), path)
.libPaths(path)
install.packages('pkgdepends')
#> Installing package into '\\AW2024/C$/Users/AlecW/AppData/Local/Temp/RtmpusLqCg'
#> (as 'lib' is unspecified)
#> also installing the dependencies 'callr', 'cli', 'curl', 'desc', 'filelock', 'jsonlite', 'lpSolve', 'pkgbuild', 'pkgcache', 'processx', 'ps', 'R6', 'zip'
#> package 'callr' successfully unpacked and MD5 sums checked
#> package 'cli' successfully unpacked and MD5 sums checked
#> package 'curl' successfully unpacked and MD5 sums checked
#> package 'desc' successfully unpacked and MD5 sums checked
#> package 'filelock' successfully unpacked and MD5 sums checked
#> package 'jsonlite' successfully unpacked and MD5 sums checked
#> package 'lpSolve' successfully unpacked and MD5 sums checked
#> package 'pkgbuild' successfully unpacked and MD5 sums checked
#> package 'pkgcache' successfully unpacked and MD5 sums checked
#> package 'processx' successfully unpacked and MD5 sums checked
#> package 'ps' successfully unpacked and MD5 sums checked
#> package 'R6' successfully unpacked and MD5 sums checked
#> package 'zip' successfully unpacked and MD5 sums checked
#> package 'pkgdepends' successfully unpacked and MD5 sums checked
#> 
#> The downloaded binary packages are in
#>  C:\Users\AlecW\AppData\Local\Temp\RtmpusLqCg\downloaded_packages
library(pkgdepends)
prop = new_pkg_installation_proposal('fs', config = list(library = .libPaths()[[1L]]))
prop$download()
#> ℹ Loading metadata database
#> ✔ Loading metadata database ... done
#> ℹ Getting 1 pkg (413.43 kB)
#> ✔ Cached copy of fs 1.6.5 (x86_64-w64-mingw32) is the latest build
plan = prop$get_install_plan()
# UNC path fails
zip::unzip(zipfile = plan$file, exdir = path)
#> Error in zip::unzip(zipfile = plan$file, exdir = path): zip error: Cannot extract entry `fs/` from archive `C:\Users\AlecW\AppData\Local\Temp\RtmpusLqCg\file284429c1b5f\bin\windows\contrib\4.4\fs_1.6.5.zip` in file zip.c:184
'fs' %in% dir(path)
#> [1] FALSE

Created on 2025-02-27 with reprex v2.1.1

Because the contents are not extracted, verify_extracted_package emits the error "{.path {filename}} is not a valid R package, it is an empty archive.".

Solution

I do not have a ready-made solution, because I believe the error is specific to the compiled code in the zip package.

Please let me know if you require any clarification! Ordinarily I would create a pull-request to try and remedy the situation, but I don't have any C++ experience.

Thank you very much!

@gaborcsardi
Copy link
Member

Thanks for the report! I assume having a package library at a UNC path work well otherwise? Eg you can install packages with install.packages and you can load them, etc.?

@awong234
Copy link
Author

awong234 commented Feb 28, 2025 via email

@awong234
Copy link
Author

awong234 commented Feb 28, 2025 via email

@awong234
Copy link
Author

awong234 commented Feb 28, 2025 via email

@gaborcsardi
Copy link
Member

Meant to say, installing source package fs failed.

So installing source packages fails with both pak and install.packages(), but if you install binaries with install.packages(), you can load and use them. E.g. if you install fs from binary you can run things like

dir(system.file(package = "fs"))
packageDescription("fs", lib.loc = .libPaths()[1])

@awong234
Copy link
Author

awong234 commented Feb 28, 2025 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants