Skip to content

Fix ARM32 internal tooling (hashFiles, etc.) defaulting to missing node24 - #243

Merged
florentianayuwono merged 2 commits into
mainfrom
fix/arm32-node24-internal-tooling
Oct 16, 2026
Merged

florentianayuwono merged 2 commits into
mainfrom
fix/arm32-node24-internal-tooling

Conversation

@florentianayuwono

Copy link
Copy Markdown

Problem

After syncing with upstream v2.338.0, armhf (linux-arm) runners started failing jobs that rely on internal runner tooling, e.g.:

Error: The template is not valid. .github/workflows/main.yaml (Line: 182, Col: 14):
An error occurred trying to start process
'/home/ubuntu/actions-runner/externals/node24/bin/node' with working directory
'.../compiler-builtins'. No such file or directory

This is not the per-action (uses:) node resolution path — that one (HandlerFactory → CheckNodeVersionForLinuxArm32) was already patched to fall back to node22 on ARM32 by #232.

Root cause

NodeUtil.GetInternalNodeVersion() is a separate code path used for internal runner tooling, not per-action JS execution:

  • hashFiles() (HashFilesFunction/NewHashFilesFunction) — the likely trigger here, via a Cargo.lock-style cache key
  • the macOS SIP re-invoker (ScriptHandler)
  • .js-shell step resolution (HostContext)
  • the NodeJsCheck/CheckUtil runner self-checks

This function unconditionally defaults to node24 (only overridable via ACTIONS_RUNNER_FORCED_INTERNAL_NODE_VERSION), with no ARM32 awareness.

Separately, Node.js upstream no longer publishes linux-armv7l builds for Node 24+, so externals.sh (already patched in this fork) only downloads node20/node22 on linux-arm. node24 simply doesn't exist on disk on armhf runners, so any of the call sites above fail with "No such file or directory".

ppc64le/s390x are unaffected — official node24 builds exist for those platforms, so no patch is needed there.

Fix

NodeUtil.GetInternalNodeVersion() now also falls back to node22 on linux-arm, mirroring the existing CheckNodeVersionForLinuxArm32 pattern used by the per-action path, while still honoring an explicit forced-version override if one is set. Added/updated NodeUtilL0.TestInternalNodeVersion (#if ARM/#else) to assert node22 as the ARM32 default.

Patch-only change (patches/runner-main-sdk8-arm.patch) — no direct src/ modifications, consistent with this fork's convention of keeping arch-specific fixes out of the upstream-synced tree.

Validation so far

  • Regenerated patch verified to apply cleanly (git apply --check) to a fresh vanilla upstream clone at the pinned baseline commit, and to this fork's current main.
  • Applied locally, full solution builds clean (./dev.sh build).
  • Targeted tests (NodeUtilL0, HandlerFactoryL0, StepHostNodeVersionL0) pass on linux-x64 (70/70) — confirms no regression to the non-ARM default (node24) path.
  • Not yet validated: actual compilation/test run under the ARM preprocessor symbol / on real armhf hardware. Opening as draft pending that verification on an arm32 runner/VM.

Other potential v2.338.0 upstream-sync fallout

Audited other direct node24 references (NodeScriptActionHandler, ActionManifestManager(Legacy)) — all are downstream of the already-patched HandlerFactory path or manifest-parsing validation only. No other ARM32/ppc64le/s390x gaps found in this pass.

…ts for linux-armv7l)

After syncing with upstream v2.338.0, armhf (linux-arm) runners started
failing with errors like:

  Error: An error occurred trying to start process
  '.../externals/node24/bin/node' ... No such file or directory

Root cause: NodeUtil.GetInternalNodeVersion() is used for *internal*
runner tooling (hashFiles(), the macOS SIP re-invoker, .js-shell steps,
and the NodeJsCheck/CheckUtil self-checks) and unconditionally defaults
to node24, with no ARM32 awareness. This is separate from the per-action
node version resolution path (HandlerFactory -> CheckNodeVersionForLinuxArm32),
which was already patched to fall back to node22 on linux-arm.

Node.js upstream no longer publishes linux-armv7l builds for Node 24+,
so externals.sh (already patched here) only downloads node20/node22 on
linux-arm - node24 is simply not present on disk, hence the failure.

Fix: GetInternalNodeVersion() now also falls back to node22 on
linux-arm, mirroring the existing CheckNodeVersionForLinuxArm32 pattern,
while still honoring an explicit ACTIONS_RUNNER_FORCED_INTERNAL_NODE_VERSION
override if set. ppc64le/s390x are unaffected since official node24
builds exist for those platforms.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The release patch lacks the fallback, and ARM32 execution remains unvalidated.

2 open findings
What changed in this PR

Updates ARM32 internal tooling to fall back from unavailable Node 24 to bundled Node 22.

Changes:

  • Adds ARM32 internal Node fallback logic.
  • Updates ARM-specific test expectations.
  • Adjusts the runner patch metadata.
File Summary
patches/​runner-main-sdk8-arm.patch Adds the ARM32 Node 22 fallback and related tests.

🧠 Review effort: Lite


💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread patches/runner-main-sdk8-arm.patch
Comment thread patches/runner-main-sdk8-arm.patch
As flagged by Copilot review: the shipped runner tarball is built from
patches/runner-sdk8-arm.patch (release.yml), not
patches/runner-main-sdk8-arm.patch (build.yml, CI-only). The release
patch's NodeUtil.cs changes only covered CheckNodeVersionForLinuxArm32
(the per-action path); it was still missing the GetInternalNodeVersion()
fallback, so actual released armhf runners would still hit the node24
'No such file or directory' failure.

Mirrors the same fix: GetInternalNodeVersion() falls back to node22 on
linux-arm, plus the equivalent #if ARM/#else NodeUtilL0 test update.

Verified: patch applies cleanly to a vanilla v2.338.0 clone, builds, and
70/70 targeted tests (NodeUtilL0/HandlerFactoryL0/StepHostNodeVersionL0)
pass on linux-x64.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@florentianayuwono

Copy link
Copy Markdown
Author

Addressed both review findings:

  1. Release patch fallback (High) - fixed in bd73083. patches/runner-sdk8-arm.patch (used by release.yml to build the actual shipped tarball) now has the same GetInternalNodeVersion() ARM32 fallback and #if ARM test coverage as runner-main-sdk8-arm.patch. Verified by applying it to a fresh vanilla v2.338.0 clone, building, and running the targeted tests (70/70 passing).

  2. ARM-specific test execution in CI (Medium) - acknowledged as a known gap, left as-is for now. CI (build.yml) intentionally only runs the L0 suite on linux-x64 (see fix(ci): correct dead L0 test matrix condition in build.yml (ISD-7073) #233), so the #if ARM branch is compiled but not executed there. Rather than reintroducing an ARM CI test leg, this will be validated manually on armhf hardware before merge, and the PR will stay in draft until that's done.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

ARM32 deprecation tracking still targets Node 20 after the Node 22 fallback, and the related documentation is outdated.

0 open findings

2 resolved since last review

🧠 Review effort: Lite

@florentianayuwono
florentianayuwono merged commit 039ea0e into main Oct 16, 2026
9 checks passed
@florentianayuwono
florentianayuwono deleted the fix/arm32-node24-internal-tooling branch October 16, 2026 03:52
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

Successfully merging this pull request may close these issues.

3 participants