Skip to content

fix(npm): resolve global bin dir under pnpm and install arm64 build on Apple Silicon - #813

Open
danielpaulus wants to merge 1 commit into
mainfrom
fix/issue-659-pnpm-postinstall-prefix
Open

fix(npm): resolve global bin dir under pnpm and install arm64 build on Apple Silicon#813
danielpaulus wants to merge 1 commit into
mainfrom
fix/issue-659-pnpm-postinstall-prefix

Conversation

@danielpaulus

@danielpaulus danielpaulus commented Aug 5, 2026

Copy link
Copy Markdown
Owner

Problem

pnpm i -g go-ios fails on macOS (reported on an M4 MacBook Air) with:

TypeError [ERR_INVALID_ARG_TYPE]: The "paths[0]" argument must be of type string. Received null
    at mkdirp ...
    at getInstallationPath (postinstall.js:50)

The log also claimed using amd64 build on M1 mac even though the machine is arm64.

Root cause

  • getInstallationPath() in npm_publish/postinstall.js only knew one way to find the global bin dir: the npm_config_prefix env var. npm always sets it, pnpm does not — so under pnpm dir stayed null and mkdirp(null) threw an opaque TypeError.
  • The darwin/arm64 branch deliberately picked the go-ios-darwin-amd64_darwin_amd64 dist dir. That predates the package shipping a go-ios-darwin-arm64_darwin_arm64 dist dir (both contain the lipo universal mac binary today), so it "worked" but installed via the amd64 path with a misleading log line.

Fix

getInstallationPath() now resolves the install dir with fallbacks, and fails loudly and helpfully instead of throwing a TypeError:

  1. npm_config_prefix (unchanged behavior for npm installs)
  2. npm_config_global_prefix (set by newer npm versions)
  3. PNPM_HOME — pnpm's global bin dir; used as-is (it is on PATH itself, no bin/ subdir)
  4. npm prefix -g output, accepted only if the command succeeds and returns an absolute path (a failure like sh: npm: command not found starts with / and must not be mistaken for a path)
  5. otherwise a clear, actionable error: set an npm prefix or run pnpm setup, then reinstall

The Windows rule is preserved for every npm-prefix-derived path (steps 1, 2, 4): on Windows the prefix itself is the bin dir, no bin/ subdir appended.

Arch handling:

  • Removed the darwin/arm64 → amd64 override; Apple Silicon Macs now get the binary from go-ios-darwin-arm64_darwin_arm64 via the normal platform/arch mapping (and no more "using amd64 build on M1 mac" log).
  • Fixed the dead process.platform === "w32" typo → "win32" in the ia32 fallback.
  • Architecture validation now runs on every platform (the old condition skipped it whenever platform === "darwin" or arch === "arm64").

Options considered

  1. Fallback chain in getInstallationPath() (chosen): npm env vars → PNPM_HOMEnpm prefix -g → clear error. Keeps npm behavior byte-identical (npm always sets npm_config_prefix, so step 1 wins there), fixes pnpm without special-casing the package manager, and degrades to an actionable message instead of a crash.
  2. Detect pnpm via npm_config_user_agent and branch per package manager: more moving parts and still needs a fallback for other managers (yarn, bun); the env-var chain covers the same cases with less code.
  3. Drop the postinstall copy entirely and use the standard package.json bin field: cleanest long-term, but a much bigger packaging change (per-platform shims or optionalDependencies split) — out of scope for a bug fix on the release path.

For darwin/arm64: kept using the shipped darwin-arm64 dist dir rather than continuing to redirect to amd64 — the dist dir exists in the published package (release workflow copies the universal binary into both), so the normal mapping is correct and the special case was only misleading.

Test plan

  • node --check npm_publish/postinstall.js passes; go build ./... && go test ./... untouched and green.
  • Local simulation of the postinstall against a fake dist/ tree on darwin/arm64:
    • pnpm scenario (npm_config_prefix unset, PNPM_HOME set): binary lands directly in $PNPM_HOME (no bin/ subdir), and the darwin-arm64 dist binary is selected.
    • npm scenario (npm_config_prefix set): binary lands in <prefix>/bin as before.
    • npm_config_global_prefix-only and npm prefix -g-only scenarios: both resolve correctly.
    • Nothing resolvable (all env vars unset, npm not on PATH): clear error message, exit code 1 (previously an opaque TypeError).
  • Canary run (publishes throwaway go-ios-canary and verifies install + run on Windows/Linux/macOS): https://github.com/danielpaulus/go-ios/actions/runs/31018210948success (published go-ios-canary@0.0.5 with this postinstall.js; install verified on macOS, Linux and Windows). Note: the first attempt of verify_install (windows-latest) hit npm registry propagation lag (ETARGET for the version macOS/Linux had already installed from the same run); a rerun of that job passed with no code change.

Related

Does not resolve #227 — that failure is a missing 32-bit linux/arm binary in dist/ (only arm64/amd64 are shipped), unrelated to the pnpm prefix crash fixed here.

Fixes #659

🤖 Generated with Claude Code

https://claude.ai/code/session_01J8eMENxJ1nec9CeHp4tjWk

…pple Silicon

getInstallationPath() assumed npm_config_prefix is always set, but pnpm
does not set it, so global installs via pnpm crashed with
"TypeError [ERR_INVALID_ARG_TYPE] ... Received null" from mkdirp(null)
(issue #659). Resolve the install dir with fallbacks:
npm_config_prefix -> npm_config_global_prefix -> PNPM_HOME (pnpm's global
bin dir, used as-is without a bin/ subdir) -> `npm prefix -g`, and fail
with a clear, actionable error message if none resolve. The Windows rule
is preserved: the npm prefix itself is the bin dir there, no bin/ subdir.

Also drop the darwin/arm64 override that installed the amd64 build (and
logged "using amd64 build on M1 mac"): the published package ships a
go-ios-darwin-arm64_darwin_arm64 dist dir (universal binary), so Apple
Silicon Macs now get it via the normal platform/arch mapping. Fix the
dead "w32" platform typo (-> "win32") in the ia32 fallback and validate
the architecture on every platform.

Fixes #659

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J8eMENxJ1nec9CeHp4tjWk
@danielpaulus

Copy link
Copy Markdown
Owner Author

/test-devices

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

🧪 Running real-device tests on PR #813run.

@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

❌ Real-device tests failed — see run.

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.

Unable to install on M4 MBA with pnpm Unable to install package on Linux.

1 participant