openclaw - ✅(Solved) Fix [Bug]: Openclaw command disappears after brew upgrade installs a new Node major [1 pull requests, 1 comments, 2 participants]

Official PRs (…)
ON THIS PAGE

Recommended Tools

×6

Utilities matched from this issue’s tags and category — try them while you read without losing context.

GitHub issue graph ai analysis

Paste a GitHub issue URL. We fetch that issue, discover linked issues from bodies/comments/timeline, collect linked pull requests, and produce a structured English report.

The report is written in English Markdown for sharing and archival.

Helpful · Quick feedback

Loading…
GitHub stats
openclaw/openclaw#80387Fetched 2026-05-11 03:15:14
View on GitHub
Comments
1
Participants
2
Timeline
4
Reactions
2
Author
Timeline (top)
labeled ×2commented ×1cross-referenced ×1

After a routine brew upgrade bumped Homebrew Node from 25.9.0_3 to 26.0.0, the openclaw command was gone from PATH with no warning. The bin shim at /opt/homebrew/bin/openclaw pointed inside the now-deleted Node 25 cellar directory, and ~/.openclaw/ config was untouched. Earlier openclaw update runs had been quietly reinstalling openclaw back inside the same per-version Node directory the version manager was about to delete, so each successful update was setting up the next breakage.

Root Cause

openclaw: command not found after the brew upgrade. /opt/homebrew/bin/openclaw was a dangling symlink into /opt/homebrew/Cellar/node/25.9.0_3/lib/node_modules/openclaw/openclaw.mjs, which no longer existed. The gateway service kept running because it had already loaded the deleted Node binary into memory, so the breakage stayed invisible until a restart or a fresh shell.

Fix Action

Fix / Workaround

Last known good: openclaw 2026.5.7 with Homebrew Node 25.9.0_3 (just before the brew upgrade). First known bad: same openclaw 2026.5.7 immediately after brew upgrade bumped Node to 26.0.0. Workaround: reinstall openclaw via the version-agnostic shimmed npm: /opt/homebrew/bin/npm install -g openclaw. That lands the install at /opt/homebrew/lib/node_modules/openclaw/ instead of the cellar.

PR fix notes

PR #80386: fix(update): Keep Openclaw alive across brew upgrade and other Node version bumps

Description (problem / solution / changelog)

Summary

  • Problem: a routine brew upgrade (or any version-manager bump to a new Node major) silently wipes the openclaw command. The operator opens a fresh shell and gets openclaw: command not found with no warning.
  • Why it matters: nothing they did caused it, and openclaw update was the thing keeping them stuck. Each successful self-update was reinstalling openclaw back inside the same per-Node directory the version manager would later delete.
  • What changed: the self-update resolver now spots per-Node ephemeral install prefixes (Homebrew Cellar, nvm, asdf, volta, fnm, n) and refuses to use the per-version npm from inside them. The fallback to PATH npm lands the install at a version-agnostic prefix that survives the next bump.
  • What did NOT change: no CLI flags, no migrations, no telemetry. Stable prefixes (/opt/homebrew/lib/node_modules, ~/.npm-global, /usr/local, etc.) resolve exactly as before.

Change Type

  • Bug fix

Scope

  • CI/CD / infra

Linked Issue/PR

  • Closes #80387
  • This PR fixes a bug or regression

Real behavior proof

  • Behavior or issue addressed: after brew upgrade bumped Homebrew Node from 25.9.0_3 to 26.0.0, openclaw was gone from PATH. The bin shim at /opt/homebrew/bin/openclaw pointed inside the deleted Node 25 cellar.

  • Real environment tested: macOS 26.4.1, Apple Silicon, Homebrew Node 26.0.0 (post-upgrade). Live ~/.openclaw/ with the gateway service still running off the in-memory copy of the now-deleted Node 25 binary.

  • Exact steps or command run after this patch: applied the same fix to the locally installed dist/update-runner-DXN2t6wW.js so the running self-update path picked it up. Reinstalled via the brew-shimmed npm: /opt/homebrew/bin/npm install -g openclaw. Confirmed the install landed at /opt/homebrew/lib/node_modules/openclaw/ instead of the cellar. Ran openclaw --version and which openclaw.

  • Evidence after fix:

    Before:

    $ which openclaw
    openclaw not found
    $ ls -la /opt/homebrew/bin/openclaw
    lrwxr-xr-x 1 sohamagents admin 73 May 4 21:27 /opt/homebrew/bin/openclaw -> /opt/homebrew/Cellar/node/25.9.0_3/lib/node_modules/openclaw/openclaw.mjs
    $ ls /opt/homebrew/Cellar/node/25.9.0_3/lib/node_modules/openclaw/openclaw.mjs
    ls: No such file or directory

    After patch + reinstall:

    $ openclaw --version
    OpenClaw 2026.5.2 (8b2a6e5)
    $ readlink /opt/homebrew/bin/openclaw
    /opt/homebrew/lib/node_modules/openclaw/openclaw.mjs
  • Observed result after fix: openclaw reachable on PATH again, anchored to the version-agnostic shared prefix. A subsequent npm install -g openclaw brought 2026.5.7 back, also under /opt/homebrew/lib/node_modules/openclaw/ rather than the cellar.

  • What was not tested: live openclaw update against fresh nvm or asdf installs. Those layouts are covered by the unit test only. The cellar repro is one-shot destructive on a maintainer machine, so re-triggering a real second brew upgrade to a new Node major was not done inside this PR.

  • Before evidence: the dangling symlink and which openclaw output above are exactly what an operator lands in after a routine brew upgrade that pulls a new Node major.

Root Cause

  • Root cause: resolvePreferredNpmCommand(pkgRoot) walks up from pkgRoot to find an adjacent bin/npm and returns it. It never checks whether that prefix is a per-Node version-manager directory the manager will later delete. Once openclaw lands in such a directory, every self-update reinstalls back into it.
  • Missing detection / guardrail: no path-shape check for the known ephemeral layouts.
  • Contributing context (if known): brew's node formula bundles its own npm whose default prefix is the cellar. Anything that invokes that bundled npm directly (a post-install script, a CI step, a tooling layer that bypasses the brew shim) lands openclaw inside the cellar. From there, self-update perpetuates it until brew deletes the dir.

Regression Test Plan

  • Coverage level that should have caught this:
    • Unit test
  • Target test or file: src/infra/update-global.test.ts, new case covering the cellar / nvm / asdf / volta / fnm / n layouts.
  • Scenario the test should lock in: when pkgRoot sits inside a per-Node prefix and the per-version bin/npm exists on disk, globalInstallArgs and globalInstallFallbackArgs both return argv whose first element is the plain "npm" command, not the per-version path.
  • Why this is the smallest reliable guardrail: the test fabricates each layout under a temp dir with a real on-disk bin/npm, so the existence check inside the resolver would otherwise succeed and the per-version npm would be picked. No live brew, nvm, asdf, volta, fnm, or n needed.
  • Existing test that already covers this (if any): no. The existing "prefers the owning npm prefix" test only covers the stable lib/node_modules shape under a brew-prefix root. It still passes after this fix.

User-visible / Behavior Changes

Healthy installs see no change. Installs currently anchored inside an ephemeral prefix get relocated to the PATH npm prefix on their next openclaw update, one-time per affected install. Operators running the daemon-managed gateway will want to restart it after the relocation.

Diagram

Before:
  openclaw update (inside /opt/homebrew/Cellar/node/X/.../openclaw/)
    -> resolvePreferredNpmCommand picks /opt/homebrew/Cellar/node/X/bin/npm
    -> npm install -g openclaw lands back in the same cellar dir
    -> brew upgrade node deletes /opt/homebrew/Cellar/node/X
    -> openclaw vanishes from PATH

After:
  openclaw update (same starting point)
    -> isEphemeralPerNodeInstallPrefix() => true => resolver returns null
    -> falls back to PATH npm
    -> install lands at a version-agnostic prefix
    -> next brew upgrade leaves openclaw intact

Security Impact

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No. The resolver still picks among existing npm binaries on disk; the only change is which one it picks.
  • Data access scope changed? No

Repro + Verification

Environment

  • OS: macOS 26.4.1 (arm64)
  • Runtime/container: Homebrew Node 26.0.0 (and Node 25.9.0_3 layout in the unit fixture)
  • Model/provider: N/A
  • Integration/channel (if any): N/A
  • Relevant config (redacted): N/A

Steps

  1. Have openclaw installed under /opt/homebrew/Cellar/node/<X>/lib/node_modules/openclaw/. Run brew upgrade node to a new major. Observe which openclaw returns "not found".
  2. Apply this patch and rebuild dist.
  3. Reinstall openclaw via the brew-shimmed npm. Confirm the install sits outside any cellar dir.
  4. Run openclaw update again and confirm the install stays at the same version-agnostic prefix.

Expected

openclaw update from inside an ephemeral prefix falls back to PATH npm. The reinstall lands at a stable prefix that survives later version-manager bumps.

Actual

After patch, matches expected. Verified via the unit test and the live dist-patch verification on the affected machine.

Evidence

  • Failing test/log before + passing after (terminal output in Real behavior proof above)
  • Trace/log snippets (which openclaw, ls -la, readlink, openclaw --version)

Human Verification

  • Verified scenarios: reproduced the broken state on the affected machine, applied the same logic to the locally installed dist file, ran openclaw --version (returned OpenClaw 2026.5.2 (8b2a6e5)), reinstalled via the brew-shimmed npm and confirmed openclaw 2026.5.7 landed at the version-agnostic prefix instead of the cellar.
  • Edge cases checked: Cellar with node@<N> (versioned formula) alongside the unversioned node formula. fnm's installation segment after the version. Stable prefixes on the same machine (/opt/homebrew, ~/.npm-global) do not match any pattern and stay unaffected.
  • What you did not verify: live openclaw update against fresh nvm or asdf installs. pnpm check:changed was not run in Testbox; targeted pnpm test src/infra/update-global.test.ts passes locally.

Review Conversations

  • I replied to or resolved every bot review conversation I addressed in this PR.
  • I left unresolved only the conversations that still need reviewer or maintainer judgment.

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No. Operators currently in an ephemeral prefix get migrated transparently on their next openclaw update.

Risks and Mitigations

  • Risk: false-positive detection on a path that happens to look like a per-Node prefix but is actually stable.
    • Mitigation: the regex patterns require version-segment shapes specific to each manager (Cellar/node/<X>, .nvm/versions/node/v<X>, etc.) and will not match generic user-chosen paths. If a false positive ever did occur, the user-visible effect is just falling back to PATH npm.

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/infra/update-global.test.ts (modified, +66/-0)
  • src/infra/update-global.ts (modified, +52/-0)

Code Example

$ which openclaw
openclaw not found
$ ls -la /opt/homebrew/bin/openclaw
lrwxr-xr-x 1 sohamagents admin 73 May 4 21:27 /opt/homebrew/bin/openclaw -> /opt/homebrew/Cellar/node/25.9.0_3/lib/node_modules/openclaw/openclaw.mjs
$ ls /opt/homebrew/Cellar/node/25.9.0_3/lib/node_modules/openclaw/openclaw.mjs
ls: No such file or directory

---

$ which openclaw
openclaw not found
$ ls -la /opt/homebrew/bin/openclaw
lrwxr-xr-x 1 sohamagents admin 73 May 4 21:27 /opt/homebrew/bin/openclaw -> /opt/homebrew/Cellar/node/25.9.0_3/lib/node_modules/openclaw/openclaw.mjs
$ ls /opt/homebrew/Cellar/node/25.9.0_3/lib/node_modules/openclaw/openclaw.mjs
ls: No such file or directory

# After applying the fix in PR #80386 and reinstalling via the brew-shimmed npm:
$ openclaw --version
OpenClaw 2026.5.2 (8b2a6e5)
$ readlink /opt/homebrew/bin/openclaw
/opt/homebrew/lib/node_modules/openclaw/openclaw.mjs
RAW_BUFFERClick to expand / collapse

Bug type

Crash (process/app exits or hangs)

Beta release blocker

No

Summary

After a routine brew upgrade bumped Homebrew Node from 25.9.0_3 to 26.0.0, the openclaw command was gone from PATH with no warning. The bin shim at /opt/homebrew/bin/openclaw pointed inside the now-deleted Node 25 cellar directory, and ~/.openclaw/ config was untouched. Earlier openclaw update runs had been quietly reinstalling openclaw back inside the same per-version Node directory the version manager was about to delete, so each successful update was setting up the next breakage.

Steps to reproduce

  1. Have openclaw installed under /opt/homebrew/Cellar/node/<X>/lib/node_modules/openclaw/ (this is what you get if any post-install or tooling step invokes the brew-bundled npm directly instead of the version-agnostic shim).
  2. Run brew upgrade (or brew upgrade node) so Homebrew bumps Node to a new major and deletes the old cellar directory.
  3. Open a fresh shell and run which openclaw. Expected the command to be on PATH. Actual: openclaw not found. Inspect /opt/homebrew/bin/openclaw and confirm the symlink target is the deleted cellar path.

Expected behavior

openclaw stays reachable on PATH across routine brew upgrade cycles. Self-update relocates the install to a version-agnostic prefix (e.g. /opt/homebrew/lib/node_modules/openclaw/) that survives Node version bumps, the same way it would behave on an install that never landed inside a cellar.

Actual behavior

openclaw: command not found after the brew upgrade. /opt/homebrew/bin/openclaw was a dangling symlink into /opt/homebrew/Cellar/node/25.9.0_3/lib/node_modules/openclaw/openclaw.mjs, which no longer existed. The gateway service kept running because it had already loaded the deleted Node binary into memory, so the breakage stayed invisible until a restart or a fresh shell.

$ which openclaw
openclaw not found
$ ls -la /opt/homebrew/bin/openclaw
lrwxr-xr-x 1 sohamagents admin 73 May 4 21:27 /opt/homebrew/bin/openclaw -> /opt/homebrew/Cellar/node/25.9.0_3/lib/node_modules/openclaw/openclaw.mjs
$ ls /opt/homebrew/Cellar/node/25.9.0_3/lib/node_modules/openclaw/openclaw.mjs
ls: No such file or directory

OpenClaw version

2026.5.7

Operating system

macOS 26.4.1 (Apple Silicon, arm64)

Install method

Homebrew Node + npm install -g openclaw (which had previously landed inside the brew Cellar via the bundled per-version npm).

Model

N/A (install/CLI plumbing, not model-related)

Provider / routing chain

N/A (install/CLI plumbing, not provider-related)

Additional provider/model setup details

N/A. Issue is in the self-update resolver in src/infra/update-global.ts, not in any provider or routing path.

Logs, screenshots, and evidence

$ which openclaw
openclaw not found
$ ls -la /opt/homebrew/bin/openclaw
lrwxr-xr-x 1 sohamagents admin 73 May 4 21:27 /opt/homebrew/bin/openclaw -> /opt/homebrew/Cellar/node/25.9.0_3/lib/node_modules/openclaw/openclaw.mjs
$ ls /opt/homebrew/Cellar/node/25.9.0_3/lib/node_modules/openclaw/openclaw.mjs
ls: No such file or directory

# After applying the fix in PR #80386 and reinstalling via the brew-shimmed npm:
$ openclaw --version
OpenClaw 2026.5.2 (8b2a6e5)
$ readlink /opt/homebrew/bin/openclaw
/opt/homebrew/lib/node_modules/openclaw/openclaw.mjs

Impact and severity

Affected: any operator whose openclaw install ended up inside a per-version Node directory (Homebrew Cellar, nvm, asdf, volta, fnm, n) and who later ran a routine version-manager bump. Severity: High. CLI vanishes silently. Gateway service keeps running on the in-memory copy of the deleted Node binary, so the breakage hides until restart or a fresh shell. Frequency: Reproducible 1/1 once you are in the trap. The trap is self-perpetuating because openclaw update would keep reinstalling into the same per-version directory. Consequence: Operators see openclaw: command not found, hunt for what they did wrong (nothing), and have to manually rebuild the install path under the new Node directory to recover.

Additional information

Last known good: openclaw 2026.5.7 with Homebrew Node 25.9.0_3 (just before the brew upgrade). First known bad: same openclaw 2026.5.7 immediately after brew upgrade bumped Node to 26.0.0. Workaround: reinstall openclaw via the version-agnostic shimmed npm: /opt/homebrew/bin/npm install -g openclaw. That lands the install at /opt/homebrew/lib/node_modules/openclaw/ instead of the cellar.

Fix proposed in PR #80386 (https://github.com/openclaw/openclaw/pull/80386). The self-update resolver now spots per-Node ephemeral install prefixes (Homebrew Cellar, nvm, asdf, volta, fnm, n) and refuses to use the per-version npm from inside them, so the fallback to PATH npm lands the install at a stable prefix that survives the next bump.

Vote matrix · Quick signals

Works
Did the solution work? Tap to confirm.
Easy Fix
Was it a quick fix?
Time Saver
Did it save you time?
Blocking
Was it severely blocking?
Common Issue
Are others likely hitting this too?
Flaky / Intermittent
Is it intermittent?
Verified / Reproducible
Can you reproduce it reliably?
Loading…

FAQ

Expected behavior

openclaw stays reachable on PATH across routine brew upgrade cycles. Self-update relocates the install to a version-agnostic prefix (e.g. /opt/homebrew/lib/node_modules/openclaw/) that survives Node version bumps, the same way it would behave on an install that never landed inside a cellar.

Still need to ship something?

×6

Another batch ranked right after the header list — different links, same matching logic.

Back to top recommendations

TRENDING

openclaw - ✅(Solved) Fix [Bug]: Openclaw command disappears after brew upgrade installs a new Node major [1 pull requests, 1 comments, 2 participants]