CI jobs fail with "node: not found" (exit 127): Alpine job image can't run JS actions #28

Closed
opened 2026-07-12 23:32:57 +00:00 by hexajon · 1 comment
hexajon commented 2026-07-12 23:32:57 +00:00 (Migrated from codeberg.org)

Summary

Every job in .forgejo/workflows/ci.yml (and the surface-diff job in
drift.yml) fails immediately on Forgejo Actions, in the checkout step (the
first step of every job), with:

OCI runtime exec failed: exec failed: unable to start container process:
exec: "node": executable file not found in $PATH
⚙️ [runner]: exitcode '127': command not found

Because it fails at checkout, no job ever reaches its actual work.

Root cause

The jobs run in container: golang:1.26-alpine. Alpine is musl-libc and ships
no Node. Forgejo Actions runs JavaScript actions (checkout, cache,
hashFiles) by executing node inside the job container, and the Node used to
run those actions is glibc-linked — it cannot exec under musl. So checkout
dies with exit 127 before running. (Same class of problem as nektos/act#107.)

The gated forgejo-smoke job in drift.yml already uses the glibc
golang:1.26 image, so it is unaffected.

Fix

Run the jobs on a glibc base image — e.g. golang:1.26-trixie (Debian) — for
all ci.yml jobs and drift.yml's surface-diff. As a consequence, the
tool-install steps that use Alpine's apk must switch to apt-get:

  • golang:1.26-trixie already ships bash, git and python3, so the gosec
    "install bash" step and the third-party-licenses apk add step are no
    longer needed.
  • hook-tests installs jq via apt-get.
  • mcp-conformance installs nodejs + npm via apt-get.
  • trixie also ships gcc, which go test -race requires.
## Summary Every job in `.forgejo/workflows/ci.yml` (and the `surface-diff` job in `drift.yml`) fails immediately on Forgejo Actions, in the `checkout` step (the first step of every job), with: OCI runtime exec failed: exec failed: unable to start container process: exec: "node": executable file not found in $PATH ⚙️ [runner]: exitcode '127': command not found Because it fails at `checkout`, no job ever reaches its actual work. ## Root cause The jobs run in `container: golang:1.26-alpine`. Alpine is musl-libc and ships no Node. Forgejo Actions runs JavaScript actions (`checkout`, `cache`, `hashFiles`) by executing `node` inside the job container, and the Node used to run those actions is glibc-linked — it cannot exec under musl. So `checkout` dies with exit 127 before running. (Same class of problem as nektos/act#107.) The gated `forgejo-smoke` job in `drift.yml` already uses the glibc `golang:1.26` image, so it is unaffected. ## Fix Run the jobs on a glibc base image — e.g. `golang:1.26-trixie` (Debian) — for all `ci.yml` jobs and `drift.yml`'s `surface-diff`. As a consequence, the tool-install steps that use Alpine's `apk` must switch to `apt-get`: - `golang:1.26-trixie` already ships bash, git and python3, so the `gosec` "install bash" step and the `third-party-licenses` `apk add` step are no longer needed. - `hook-tests` installs `jq` via `apt-get`. - `mcp-conformance` installs `nodejs` + `npm` via `apt-get`. - trixie also ships `gcc`, which `go test -race` requires.
hexajon commented 2026-07-14 21:33:14 +00:00 (Migrated from codeberg.org)

Already resolved on main before this branch started: PR #27 (commit 36efc3a7, "fix(ci): run jobs on Debian glibc image so JS actions get a working node") made exactly this change. Verified against main at df485cee by an independent build+review pass: all 14 ci.yml jobs and drift.yml's surface-diff run on docker.io/golang:1.26-trixie (glibc, pinned by digest); no apk steps remain (jq via apt-get in hook-tests, nodejs+npm via apt-get in mcp-conformance; trixie ships bash/python3/gcc so the gosec and third-party-licenses install steps are gone); forgejo-smoke untouched; both YAML files parse; Go stays 1.26; full gate green. The dev branch for this issue had zero delta vs main, so there is nothing to merge.

Already resolved on main before this branch started: PR #27 (commit 36efc3a7, "fix(ci): run jobs on Debian glibc image so JS actions get a working node") made exactly this change. Verified against main at df485cee by an independent build+review pass: all 14 ci.yml jobs and drift.yml's surface-diff run on docker.io/golang:1.26-trixie (glibc, pinned by digest); no apk steps remain (jq via apt-get in hook-tests, nodejs+npm via apt-get in mcp-conformance; trixie ships bash/python3/gcc so the gosec and third-party-licenses install steps are gone); forgejo-smoke untouched; both YAML files parse; Go stays 1.26; full gate green. The dev branch for this issue had zero delta vs main, so there is nothing to merge.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
sixfold-space/madtea#28
No description provided.