-
Notifications
You must be signed in to change notification settings - Fork 49
Description
Error description
Functions exported from box modules fail when used with future.apply::future_lapply() for parallel processing. The error occurs during environment serialisation when future attempts to export the function to worker processes.
Error message:
Error in parent.env<-(tmp, value = ) :
cycles in parent chains are not allowed
This appears to be caused by box's module environment structure creating cyclic parent chains that R 4.5+ rejects during serialisation. The same code works perfectly when defined in a regular script (without box).
Minimal Reproducible Example
mre_module.R (the box module):
#' @export
run_parallel <- function(items) {
worker <- function(x) {
return(x^2)
}
results <- future.apply::future_lapply(items, worker, future.seed = TRUE)
return(unlist(results))
}mre_test.R (the test script):
#!/usr/bin/env Rscript
# Import the function from a box module
box::use(./mre_module[run_parallel])
# Setup parallel
future::plan(future::multisession, workers = 2)
# This fails with "cycles in parent chains are not allowed"
result <- run_parallel(1:5)
print(result)
future::plan(future::sequential)Run with:
Rscript mre_test.R
Output:
Warning: Caught simpleError. Canceling all iterations ...
Error in `parent.env<-`(`*tmp*`, value = <environment>) :
cycles in parent chains are not allowed
Calls: run_parallel ... tryCatchList -> tryCatchOne -> <Anonymous> -> onError
Execution halted
Expected behaviour
The function should execute in parallel and return [1] 1 4 9 16 25, as it does when the same code is defined outside of a box module.
Workaround confirmation
The identical code works when not using box:
#!/usr/bin/env Rscript
run_parallel <- function(items) {
worker <- function(x) {
return(x^2)
}
results <- future.apply::future_lapply(items, worker, future.seed = TRUE)
return(unlist(results))
}
future::plan(future::multisession, workers = 2)
result <- run_parallel(1:5)
print(result) # Works: [1] 1 4 9 16 25
future::plan(future::sequential)Investigation notes
I've done some research into this issue:
- R 4.5 change: R's internal code for changing environment parents now signals an error if the change would create a cycle in the parent chain (R NEWS).
- Related issues: This appears related to Cannot use
future/future_lapplyandboxtogether:Error in env$.packageName : name '.packageName' not found in 'env' Calls: <Anonymous> ... cleanup.Globals -> isPackageNamespace -> $ -> $.box$mod Execution halted#285 and Make boxfuture-proof #314, though those were closed after fixes to the globals package (v0.16.2). However, this environment cycle issue persists with current package versions. - Root cause hypothesis: When future.apply serialises a function's closure to send to worker processes, it traverses the environment chain. Box modules create complex environment hierarchies for namespacing, and somewhere in this chain there appears to be a cyclic reference that R 4.5+ now rejects.
- Tested variations: I've tried various approaches (defining workers at module level, using :: instead of $, explicit future.globals specification, eval() in different environments) — all fail when the calling function is exported from a box module.
R version
> R.version
_
platform aarch64-apple-darwin20
arch aarch64
os darwin20
system aarch64, darwin20
status
major 4
minor 5.1
year 2025
month 06
day 13
svn rev 88306
language R
version.string R version 4.5.1 (2025-06-13)
nickname Great Square Root
---
> sessionInfo()
R version 4.5.1 (2025-06-13)
Platform: aarch64-apple-darwin20
Running under: macOS Sequoia 15.5
Matrix products: default
BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/4.5-arm64/Resources/lib/libRlapack.dylib; LAPACK version 3.12.1
locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8
time zone: America/Mexico_City
tzcode source: internal
attached base packages:
[1] stats graphics grDevices utils datasets methods base
other attached packages:
[1] future.apply_1.20.1 future_1.69.0
loaded via a namespace (and not attached):
[1] digest_0.6.37 R6_2.6.1 codetools_0.2-20
[4] lubridate_1.9.4 parallel_4.5.1 timechange_0.3.0
[7] generics_0.1.4 cli_3.6.5 parallelly_1.46.1
[10] renv_1.1.4 data.table_1.17.8 compiler_4.5.1
[13] globals_0.18.0 tools_4.5.1 listenv_0.10.0
[16] rlang_1.1.6 fs_1.6.6 box_1.2.1
>
‘box’ version
‘1.2.1’