From 26bcc9566549e79e9b3b1cf4b41b7790cd32d718 Mon Sep 17 00:00:00 2001 From: brokemac79 Date: Mon, 18 May 2026 21:55:16 +0100 Subject: [PATCH] fix(update): guide EACCES manual recovery --- docs/install/updating.md | 32 +++++++++++++++++++++++++---- src/cli/update-cli/progress.test.ts | 4 ++++ src/cli/update-cli/progress.ts | 6 ++++++ 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/docs/install/updating.md b/docs/install/updating.md index 6547ff2c5f5..b498eea9a4f 100644 --- a/docs/install/updating.md +++ b/docs/install/updating.md @@ -98,10 +98,34 @@ npm i -g openclaw@latest ``` Prefer `openclaw update` for supervised installs because it can coordinate the -package swap with the running Gateway service. If you update manually while a -managed Gateway is running, restart the Gateway immediately after the package -manager finishes so the old process does not keep serving from replaced package -files. +package swap with the running Gateway service. If you update manually on a +supervised install, stop the managed Gateway before the package manager starts. +Package managers replace files in place, and a running Gateway can otherwise try +to load core or plugin files while the package tree is temporarily half-swapped. +Restart the Gateway after the package manager finishes so the service picks up +the new install. + +For a root-owned Linux system-global install, if `openclaw update` fails with +`EACCES` and you recover with system npm, keep the Gateway stopped through the +manual package replacement. Use the same `openclaw` profile flags or environment +you normally use for that Gateway. Replace `/usr/bin/npm` with the system npm +that owns the root-owned global prefix on your host: + +```bash +openclaw gateway stop +sudo /usr/bin/npm i -g openclaw@latest +openclaw gateway install --force +openclaw gateway restart +``` + +Then verify the service: + +```bash +openclaw --version +curl -fsS http://127.0.0.1:18789/readyz +openclaw plugins list --json +openclaw doctor --deep --lint --json +``` When `openclaw update` manages a global npm install, it installs the target into a temporary npm prefix first, verifies the packaged `dist` inventory, then swaps diff --git a/src/cli/update-cli/progress.test.ts b/src/cli/update-cli/progress.test.ts index 89329d13ad7..a9eea2e4ed1 100644 --- a/src/cli/update-cli/progress.test.ts +++ b/src/cli/update-cli/progress.test.ts @@ -64,6 +64,7 @@ describe("inferUpdateFailureHints", () => { const hints = inferUpdateFailureHints(result); expect(hints.join("\n")).toContain("EACCES"); expect(hints.join("\n")).toContain("npm config set prefix ~/.local"); + expect(hints.join("\n")).toContain("stop the Gateway first"); }); it("returns EACCES hint for staged package permission failures", () => { @@ -74,6 +75,9 @@ describe("inferUpdateFailureHints", () => { const hints = inferUpdateFailureHints(result); expect(hints.join("\n")).toContain("EACCES"); expect(hints.join("\n")).toContain("npm config set prefix ~/.local"); + expect(hints.join("\n")).toContain(""); + expect(hints.join("\n")).toContain("gateway install --force"); + expect(hints.join("\n")).toContain("gateway restart"); }); it("returns native optional dependency hint for node-gyp failures", () => { diff --git a/src/cli/update-cli/progress.ts b/src/cli/update-cli/progress.ts index 61797ffd3c0..2cb4186128f 100644 --- a/src/cli/update-cli/progress.ts +++ b/src/cli/update-cli/progress.ts @@ -85,7 +85,13 @@ export function inferUpdateFailureHints(result: UpdateRunResult): string[] { hints.push( "Detected permission failure (EACCES). Re-run with a writable global prefix or sudo (for system-managed Node installs).", ); + hints.push( + "If you recover with sudo/manual package install on a managed Gateway, stop the Gateway first so it does not load files while the package tree is being replaced.", + ); hints.push("Example: npm config set prefix ~/.local && npm i -g openclaw@latest"); + hints.push( + "System install outline: openclaw gateway stop -> sudo i -g openclaw@latest -> openclaw gateway install --force -> openclaw gateway restart.", + ); } if (