openclaw - 💡(How to fix) Fix Bug: update dev-channel switch can leave npm-global openclaw as source checkout symlink [2 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#74597Fetched 2026-04-30 06:22:27
View on GitHub
Comments
2
Participants
2
Timeline
3
Reactions
2
Timeline (top)
commented ×2cross-referenced ×1

On a normal npm-global OpenClaw install, the updater can appear to switch from package mode to git/source mode and run a global install against the git checkout path. On this host that left the global package root as a symlink:

~/.npm-global/lib/node_modules/openclaw -> ../../../../../opt/openclaw-source

That broke the gateway after a later update because systemd/CLI executed stale source-checkout code while plugins/config expected the newer package layout.

Root Cause

That broke the gateway after a later update because systemd/CLI executed stale source-checkout code while plugins/config expected the newer package layout.

Code Example

~/.npm-global/lib/node_modules/openclaw -> ../../../../../opt/openclaw-source

---

src/cli/update-cli/update-command.ts
switchToGit = requestedChannel === "dev" && installKind !== "git"
updateRoot = resolveGitInstallDir()
ensureGitCheckout(updateRoot)
runGatewayUpdate({ cwd: updateRoot, argv1: undefined, channel: ... })
globalInstallArgs(installTarget, updateRoot)

---

npm i -g /opt/openclaw-source
RAW_BUFFERClick to expand / collapse

Summary

On a normal npm-global OpenClaw install, the updater can appear to switch from package mode to git/source mode and run a global install against the git checkout path. On this host that left the global package root as a symlink:

~/.npm-global/lib/node_modules/openclaw -> ../../../../../opt/openclaw-source

That broke the gateway after a later update because systemd/CLI executed stale source-checkout code while plugins/config expected the newer package layout.

Evidence from affected host

  • Bad symlink timestamp: Apr 26, 2026 around 21:53 CDT.
  • Same window had source-build/update activity:
    • pnpm tooling under ~/.local/share/pnpm/.tools around 21:42
    • /opt/openclaw-source/node_modules populated around 21:46-21:52
    • /opt/openclaw-source/dist and dist-runtime written around 21:52-21:53
  • No npm debug log was found for the 21:40-22:10 window, so this does not look like a normal standalone npm install -g openclaw.
  • Before repair, the service entrypoint resolved through the global npm path into /opt/openclaw-source.
  • Manual repair was to replace the symlink with a real package install: npm install -g [email protected], then regenerate/repair service state.

Suspected mechanism

In the update CLI source, when requestedChannel === "dev" && installKind !== "git", the update path switches package installs to a git checkout. The code path then uses the git checkout as the install spec for the global install:

src/cli/update-cli/update-command.ts
switchToGit = requestedChannel === "dev" && installKind !== "git"
updateRoot = resolveGitInstallDir()
ensureGitCheckout(updateRoot)
runGatewayUpdate({ cwd: updateRoot, argv1: undefined, channel: ... })
globalInstallArgs(installTarget, updateRoot)

For npm, that is effectively:

npm i -g /opt/openclaw-source

On this host that resulted in the global package root being a symlink to the source checkout.

Expected behavior

A normal npm-global install should not silently become a global symlink to a mutable git/source checkout. If dev-channel switching is intentional, the updater/status/doctor should make that explicit and ensure the service/plugin runtime cannot end up in a mixed stale-source/package state.

Suggested fixes

  • openclaw update should not leave global node_modules/openclaw as a symlink to the source checkout unless explicitly requested and clearly reported.
  • openclaw update --json should return a failing exit code when it reports status: "skipped" for dirty git/source state, or callers should otherwise have a reliable failure signal.
  • openclaw status / doctor should flag when a package install's global root resolves to a git checkout/source tree.
  • Post-update verification should assert the service entrypoint, package root, plugin sidecar roots, and reported install kind agree.

Impact

High for package-installed gateways: a later update/restart can fail hard because the service executes stale source-checkout code while the rest of the runtime expects the current npm package/plugin layout.

extent analysis

TL;DR

The updater should be modified to avoid silently switching to a git/source mode and creating a global symlink to the source checkout, instead ensuring a normal npm-global install.

Guidance

  • Verify the update-command.ts code to ensure it handles the requestedChannel === "dev" && installKind !== "git" case correctly, avoiding the creation of a global symlink to the source checkout.
  • Modify the openclaw update command to explicitly report when switching to a git/source mode and ensure the service/plugin runtime is aware of the change.
  • Implement post-update verification to assert that the service entrypoint, package root, plugin sidecar roots, and reported install kind agree, preventing mixed stale-source/package states.
  • Consider adding a check in openclaw status / doctor to flag when a package install's global root resolves to a git checkout/source tree.

Example

No code snippet is provided as the issue does not contain sufficient information to create a concrete example.

Notes

The suggested fixes and guidance are based on the provided issue content and may not be exhaustive. Additional modifications may be necessary to fully resolve the issue.

Recommendation

Apply workaround: Modify the openclaw update command to avoid silently switching to a git/source mode and ensure a normal npm-global install, as this will prevent the creation of a global symlink to the source checkout and reduce the risk of mixed stale-source/package states.

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

A normal npm-global install should not silently become a global symlink to a mutable git/source checkout. If dev-channel switching is intentional, the updater/status/doctor should make that explicit and ensure the service/plugin runtime cannot end up in a mixed stale-source/package state.

Still need to ship something?

×6

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

Back to top recommendations

TRENDING