Skip to content

Fix R-devel R CMD check on GHA - Now temporarily disabled #143

Open

Description

@GegznaV

R-CMD-check on R-Devel on GHA fails. Currently I do not know how to fix that. So I will temorarily disable that paericular job - some working tests are better than no tests. Some context especially for AI assistance is below.

Related:

Details ----

GHA R-devel Roxygenize Failure — Debug Log & AI Context

Problem Statement

R CMD check on GHA fails exclusively on ubuntu-latest (R-devel).
The error is always one of:

  • undefined symbol: SET_GROWABLE_BIT — roxygen2 .so cannot load under R-devel
  • ERROR: a 'NAMESPACE' file is required — NAMESPACE was deleted before the crash

Root Cause Analysis

C ABI Break in R 4.6.0 (R-devel)

R 4.6.0 (r89670, March 2026) removed SET_GROWABLE_BIT from libR.so exported symbols — it became a static inline in R.h. Any roxygen2 binary compiled against R ≤ 4.5.x references this as an external symbol and cannot be loaded under R-devel.

roxygen2 7.3.x parser_setMethod Bug

roxygen2 ≥ 7.3.0 introduced a bug in parser_setMethod: it calls methods::getMethod(name, eval(call$signature), where = env) with no error handling. In a clean Rscript session, S4 method tables for primitives ([[, [, $, etc.) are not populated → crash.

hyperSpec has ~60+ setMethod() calls on primitives, making it particularly vulnerable.


Timeline of Fix Attempts

✅ Session 1 — all.equal S4 → S3 conversion

  • Problem: roxygen2 7.3.3 crashed on setMethod("all.equal", ...) (S3 generic + S4 registration)
  • Fix: Converted to S3 all.equal.hyperSpec <- .all.equal with @method all.equal hyperSpec @export
  • Outcome: ✅ Fixed locally. NAMESPACE updated to S3method(all.equal,hyperSpec)

✅ Session 2–3 — Pin roxygen2 to 7.2.3 on GHA

  • Problem: roxygen2 7.3.x crashes on setMethod("[[", ...) (S4 method on primitive) — cannot be fixed without rewriting ~60 S4 methods
  • Fix: GHA workflow pins to remotes::install_version("roxygen2", "7.2.3")
  • Outcome: ✅ Works on macOS/Windows/ubuntu release & oldrel

❌ Session 3 mistake — Removed the pin

  • Problem: Pin was removed thinking the all.equal fix was sufficient
  • Outcome: ❌ GHA failed on ALL platforms with parser_setMethod crash

❌ Attempt A — Pin 7.2.3 binary on R-devel

  • Assumption: Same pin would work for R-devel
  • Outcome: ❌ undefined symbol: SET_GROWABLE_BIT — binary compiled against older R ABI

❌ Attempt B — Compile roxygen2 7.2.3 from source on R-devel

  • Code: remotes::install_version("roxygen2", "7.2.3", type = "source")
  • Assumption: Source compilation against R-devel headers would avoid the symbol issue
  • Outcome: ❌ Same error — source-compiled 7.2.3 also references SET_GROWABLE_BIT as external symbol (Rcpp or R-internal headers in 7.2.3 still emit the reference)

❌ Attempt C — Skip Roxygenize step on R-devel + restore from git

  • Code: if: matrix.config.r != 'devel' on the Roxygenize step; separate "Restore NAMESPACE" step with git checkout HEAD -- NAMESPACE man/
  • Assumption: if: condition would prevent Roxygenize from running; setup-r-dependencies with local:. would not wipe NAMESPACE
  • Outcome: ❌ Still fails — devtools::document() still runs and still hits the SET_GROWABLE_BIT error
  • Analysis: Either (a) GHA if: step conditions don't reliably prevent execution in all scenarios, (b) the GHA run shown was from a pre-fix commit, or (c) setup-r-dependencies itself triggers devtools::document() internally via pak's local package installation

❌ Attempt D — tryCatch in Roxygenize step body (current)

  • Code: Run Roxygenize on ALL platforms; wrap in tryCatch; on failure system2("git", c("checkout", "HEAD", "--", "NAMESPACE", "man/")) and continue
  • Rationale: Eliminates reliance on if: conditions; self-healing; handles ALL failure modes:
    • Mode 1: dyn.load(roxygen2.so) fails → error caught → git restore → continue (NAMESPACE NOT wiped)
    • Mode 2: roxygen2 loads, parser_setMethod crashes after deleting NAMESPACE → error caught → git restore → continue
  • Removed: Separate "Restore NAMESPACE and man/ from git" step, sed -i '/^RoxygenNote:/d' DESCRIPTION modification
  • Outcome: 🔄 Testing

Key Facts

Fact Verified
roxygen2 7.3.3 RSPM binary fails on R-devel (SET_GROWABLE_BIT) ✅ Yes
roxygen2 7.2.3 RSPM binary fails on R-devel (SET_GROWABLE_BIT) ✅ Yes
roxygen2 7.2.3 source-compiled fails on R-devel (SET_GROWABLE_BIT) ✅ Yes
roxygen2 7.3.3 loads on R release (4.5.3) but crashes on [[ setMethod ✅ Yes
roxygen2 7.2.3 works correctly on R release ✅ Yes
setup-r-dependencies wipes NAMESPACE ❓ Unclear — pak does R CMD INSTALL, NOT devtools::document()
Roxygenize step if: matrix.config.r != 'devel' prevents execution ❓ Unclear — error still shows in log

How Similar S4 Repos Handle This

  • Bioconductor (BiocGenerics, S4Vectors, IRanges): Pre-commit NAMESPACE and man/, skip roxygenize in CI, or don't use roxygen2 at all
  • Matrix CRAN package: Hand-written Rd files, no roxygen2 in CI
  • Common pattern: The Roxygenize step uses tryCatch() → on failure, restore from git and continue with committed docs

Current Strategy (Attempt D — tryCatch)

Use tryCatch in the Roxygenize step instead of relying on if: conditions:

ok <- tryCatch({
  devtools::document()
  TRUE
}, error = function(e) {
  message("devtools::document() failed: ", conditionMessage(e))
  message("Restoring NAMESPACE and man/ from committed versions...")
  system2("git", c("checkout", "HEAD", "--", "NAMESPACE", "man/"))
  FALSE
})
if (!ok) message("Using committed documentation.")

Why this is correct:

  • On R-devel: dyn.load(roxygen2.so) fails before touching NAMESPACE → error caught → git checkout is a no-op (NAMESPACE intact) → continue with committed docs ✅
  • On R-devel (if parker_setMethod crashes after NAMESPACE deletion): error caught → git checkout restores → continue ✅
  • On R release/oldrel (with pinned 7.2.3): devtools::document() succeeds → no error → continue with fresh docs ✅
  • No if: conditions to debug or misfire ✅

Companion changes:

  • "Restore NAMESPACE and man/ from git (R-devel)" step removed (handled inside Roxygenize)
  • sed -i '/^RoxygenNote:/d' DESCRIPTION removed (was a hack; RoxygenNote should stay)
  • Session info step re-added (was accidentally dropped) using sessioninfo::session_info()

How Similar S4 Repositories Handle This

  • Bioconductor (BiocGenerics, S4Vectors, IRanges): Pre-commit NAMESPACE and man/, skip roxygenize in CI entirely, or don't use roxygen2
  • Matrix (CRAN): Hand-written Rd files, no roxygen2 in CI pipeline
  • Common CRAN S4 packages: Pre-commit docs and use tryCatch or non-roxygenize CI flows
  • Best practice: When breaking R API changes occur (like 4.6.0 ABI break), use defensive tryCatch rather than OS/version conditions

Activity

  1. changed the title [-]Fix R-devel check on GHT - Temporarily disabled[/-] [+]Fix R-devel R CMD check on GHA - Now temporarily disabled[/+] on Mar 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions