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
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 checkon GHA fails exclusively on ubuntu-latest (R-devel).The error is always one of:
undefined symbol: SET_GROWABLE_BIT— roxygen2.socannot load under R-develERROR: a 'NAMESPACE' file is required— NAMESPACE was deleted before the crashRoot Cause Analysis
C ABI Break in R 4.6.0 (R-devel)
R 4.6.0 (r89670, March 2026) removed
SET_GROWABLE_BITfromlibR.soexported symbols — it became a static inline inR.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_setMethodBugroxygen2 ≥ 7.3.0 introduced a bug in
parser_setMethod: it callsmethods::getMethod(name, eval(call$signature), where = env)with no error handling. In a cleanRscriptsession, 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
setMethod("all.equal", ...)(S3 generic + S4 registration)all.equal.hyperSpec <- .all.equalwith@method all.equal hyperSpec @exportS3method(all.equal,hyperSpec)✅ Session 2–3 — Pin roxygen2 to 7.2.3 on GHA
setMethod("[[", ...)(S4 method on primitive) — cannot be fixed without rewriting ~60 S4 methodsremotes::install_version("roxygen2", "7.2.3")❌ Session 3 mistake — Removed the pin
all.equalfix was sufficientparser_setMethodcrash❌ Attempt A — Pin 7.2.3 binary on R-devel
undefined symbol: SET_GROWABLE_BIT— binary compiled against older R ABI❌ Attempt B — Compile roxygen2 7.2.3 from source on R-devel
remotes::install_version("roxygen2", "7.2.3", type = "source")SET_GROWABLE_BITas 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
if: matrix.config.r != 'devel'on the Roxygenize step; separate "Restore NAMESPACE" step withgit checkout HEAD -- NAMESPACE man/if:condition would prevent Roxygenize from running;setup-r-dependencieswithlocal:.would not wipe NAMESPACEdevtools::document()still runs and still hits theSET_GROWABLE_BITerrorif: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-dependenciesitself triggersdevtools::document()internally via pak's local package installation❌ Attempt D —
tryCatchin Roxygenize step body (current)tryCatch; on failuresystem2("git", c("checkout", "HEAD", "--", "NAMESPACE", "man/"))and continueif:conditions; self-healing; handles ALL failure modes:dyn.load(roxygen2.so)fails → error caught → git restore → continue (NAMESPACE NOT wiped)sed -i '/^RoxygenNote:/d'DESCRIPTION modificationKey Facts
[[setMethodsetup-r-dependencieswipes NAMESPACEif: matrix.config.r != 'devel'prevents executionHow Similar S4 Repos Handle This
BiocGenerics,S4Vectors,IRanges): Pre-commit NAMESPACE and man/, skip roxygenize in CI, or don't use roxygen2 at alltryCatch()→ on failure, restore from git and continue with committed docsCurrent Strategy (Attempt D — tryCatch)
Use
tryCatchin the Roxygenize step instead of relying onif:conditions:Why this is correct:
dyn.load(roxygen2.so)fails before touching NAMESPACE → error caught →git checkoutis a no-op (NAMESPACE intact) → continue with committed docs ✅git checkoutrestores → continue ✅devtools::document()succeeds → no error → continue with fresh docs ✅if:conditions to debug or misfire ✅Companion changes:
sed -i '/^RoxygenNote:/d' DESCRIPTIONremoved (was a hack;RoxygenNoteshould stay)sessioninfo::session_info()How Similar S4 Repositories Handle This
BiocGenerics,S4Vectors,IRanges): Pre-commit NAMESPACE and man/, skip roxygenize in CI entirely, or don't use roxygen2tryCatchor non-roxygenize CI flowstryCatchrather than OS/version conditions