Skip to content

Symlink the active nvm Node binaries into /usr/local/bin - #24

Merged
TomProkop merged 1 commit into
masterfrom
fix-node-path-shadowing
Aug 24, 2026
Merged

Symlink the active nvm Node binaries into /usr/local/bin#24
TomProkop merged 1 commit into
masterfrom
fix-node-path-shadowing

Conversation

@TomProkop

Copy link
Copy Markdown
Member

Summary

Found while verifying the pre-built image end-to-end in a real Docker daemon: node --version
reported 18.19.1 (the apt-based bootstrap install-features.sh installs first just to get npm
working), not the pinned 22 from devcontainer.features.json, even though the node Feature's
own install.sh completes successfully and installs 22 via nvm without error.

Root cause: nvm only reaches PATH through /etc/profile.d or shell rc files sourced by a
login shell. Neither Claude Code's Bash tool, a GitHub Actions step, nor docker run ... bash -c is one — same class of bug the existing link_dotnet_wrapper mechanism already exists to work
around for dotnet/pac/txc, just never extended to node.

Fix: symlink node/npm/npx/corepack from nvm's current (a stable, version-tracking
symlink nvm maintains) into /usr/local/bin, which already takes precedence over /usr/bin in
the default PATH — no wrapper script needed since node requires no extra env var at run time,
unlike dotnet needing DOTNET_ROOT.

Verification

Built the current Dockerfile locally end-to-end (fresh, --no-cache) and confirmed in a running
container:

  • Before this fix: node --versionv18.19.1, which node/usr/bin/node.
  • After this fix: node --versionv22.23.2, npm --version10.9.8, both resolving via
    /usr/local/bin/.
  • All other tools (dotnet, az, pwsh, terraform, gh, copilot, func, pac, txc)
    confirmed working, DOTNET_ROOT correctly wired, pac/txc work with no PATH hacks, and the
    pac/txc auto-update marker files are present.

Generated by Claude Code

The node Feature installs via nvm, which only reaches PATH through
/etc/profile.d or shell rc files sourced by a login shell — neither
Claude Code's Bash tool, a GitHub Actions step, nor `docker run ...
bash -c` is one, so plain `node`/`npm` silently resolved to whatever
older version happened to already be on the default PATH (18.19.1,
the apt-based bootstrap this same script installs first to get npm
working at all) instead of the pinned 22. Same class of bug the
dotnet wrapper below already exists for, just never extended to
node. Confirmed by building the image locally: node stayed at
18.19.1 despite the node Feature installing 22 successfully via nvm.

Symlinks node/npm/npx/corepack from nvm's `current` (a stable,
version-tracking symlink) into /usr/local/bin, which already takes
precedence over /usr/bin in the default PATH - no wrapper script
needed since node requires no extra env var at run time, unlike
dotnet needing DOTNET_ROOT.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PeQipf4QUFGFaVceX8NcEP
@TomProkop
TomProkop merged commit d2d0582 into master Aug 24, 2026
2 checks passed
@TomProkop
TomProkop deleted the fix-node-path-shadowing branch August 24, 2026 13:44
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.

2 participants