Skip to content

Session watcher never attaches on R >= 4.6 — startup no longer calls the globalenv .First.sys override armed by init.R (plots silently fall back to Rplots.pdf) #1725

Description

@davidkane9

Summary

vscode-R's session watcher attaches via R/session/init.R, which assigns a .First.sys shadow into the global environment during profile loading and relies on R's startup invoking it after default packages load (init_firstassign(".First.sys", init_last, envir = globalenv())). On R 4.6.x, R's startup no longer calls a globalenv .First.sys override — the shadow is armed but never invoked — so the watcher never attaches, options(device=...) is never set, and every plot() in the R terminal silently writes Rplots.pdf. No error appears anywhere, which makes this brutal to diagnose in teaching environments.

Verified empirically with a minimal profile (no extension involved):

cat > /tmp/profile.R <<'PROF'
first_sys_orig <- .First.sys
.First.sys <- function() {
    first_sys_orig()
    writeLines("fired", "/tmp/fired")
}
PROF
rm -f /tmp/fired
R_PROFILE_USER=/tmp/profile.R R -q --no-save -e 'invisible(NULL)'
ls /tmp/fired
  • R 4.5.3 (macOS): marker created — shadow honored.
  • R 4.6.1 (Linux, rocker image): marker never created — shadow bypassed.

Same result across consoles (plain R and custom front ends alike), since the change is in R's own startup, not any front end. We could not find the change documented in the R 4.6.0/4.6.1 NEWS; it may be a side effect of internal startup refactoring.

Observed in the wild

vscode-R 2.8.8 + GitHub Codespaces + R 4.6.1: after startup, exists(".First.sys", envir=globalenv(), inherits=FALSE) is TRUE (armed, unfired), "tools:vscode" %in% search() is FALSE, plot()Rplots.pdf. Manually calling .First.sys() attaches the watcher and everything works from then on — only the startup invocation is missing.

Workaround we ship (site profile)

.First <- function() {
    fs <- globalenv()$.First.sys
    if (is.function(fs)) fs()
}

R still honors the documented .First() user hook after all profiles, so this fires the armed shadow; it's a no-op outside vscode-R sessions. Works on R 4.6.1 (CI-tested). The extension could adopt something equivalent in profile.R/init.R (e.g., arrange the deferred init via .First, or a top-level task callback) rather than relying on the .First.sys override that R >= 4.6 ignores.

Happy to test a fix — we ship vscode-R to a large intro data-science course.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions