Skip to content

Commit 26bcc95

Browse files
brokemac79steipete
authored andcommitted
fix(update): guide EACCES manual recovery
1 parent 583eb71 commit 26bcc95

3 files changed

Lines changed: 38 additions & 4 deletions

File tree

docs/install/updating.md

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,34 @@ npm i -g openclaw@latest
9898
```
9999

100100
Prefer `openclaw update` for supervised installs because it can coordinate the
101-
package swap with the running Gateway service. If you update manually while a
102-
managed Gateway is running, restart the Gateway immediately after the package
103-
manager finishes so the old process does not keep serving from replaced package
104-
files.
101+
package swap with the running Gateway service. If you update manually on a
102+
supervised install, stop the managed Gateway before the package manager starts.
103+
Package managers replace files in place, and a running Gateway can otherwise try
104+
to load core or plugin files while the package tree is temporarily half-swapped.
105+
Restart the Gateway after the package manager finishes so the service picks up
106+
the new install.
107+
108+
For a root-owned Linux system-global install, if `openclaw update` fails with
109+
`EACCES` and you recover with system npm, keep the Gateway stopped through the
110+
manual package replacement. Use the same `openclaw` profile flags or environment
111+
you normally use for that Gateway. Replace `/usr/bin/npm` with the system npm
112+
that owns the root-owned global prefix on your host:
113+
114+
```bash
115+
openclaw gateway stop
116+
sudo /usr/bin/npm i -g openclaw@latest
117+
openclaw gateway install --force
118+
openclaw gateway restart
119+
```
120+
121+
Then verify the service:
122+
123+
```bash
124+
openclaw --version
125+
curl -fsS http://127.0.0.1:18789/readyz
126+
openclaw plugins list --json
127+
openclaw doctor --deep --lint --json
128+
```
105129

106130
When `openclaw update` manages a global npm install, it installs the target into
107131
a temporary npm prefix first, verifies the packaged `dist` inventory, then swaps

src/cli/update-cli/progress.test.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ describe("inferUpdateFailureHints", () => {
6464
const hints = inferUpdateFailureHints(result);
6565
expect(hints.join("\n")).toContain("EACCES");
6666
expect(hints.join("\n")).toContain("npm config set prefix ~/.local");
67+
expect(hints.join("\n")).toContain("stop the Gateway first");
6768
});
6869

6970
it("returns EACCES hint for staged package permission failures", () => {
@@ -74,6 +75,9 @@ describe("inferUpdateFailureHints", () => {
7475
const hints = inferUpdateFailureHints(result);
7576
expect(hints.join("\n")).toContain("EACCES");
7677
expect(hints.join("\n")).toContain("npm config set prefix ~/.local");
78+
expect(hints.join("\n")).toContain("<system-npm>");
79+
expect(hints.join("\n")).toContain("gateway install --force");
80+
expect(hints.join("\n")).toContain("gateway restart");
7781
});
7882

7983
it("returns native optional dependency hint for node-gyp failures", () => {

src/cli/update-cli/progress.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,13 @@ export function inferUpdateFailureHints(result: UpdateRunResult): string[] {
8585
hints.push(
8686
"Detected permission failure (EACCES). Re-run with a writable global prefix or sudo (for system-managed Node installs).",
8787
);
88+
hints.push(
89+
"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.",
90+
);
8891
hints.push("Example: npm config set prefix ~/.local && npm i -g openclaw@latest");
92+
hints.push(
93+
"System install outline: openclaw gateway stop -> sudo <system-npm> i -g openclaw@latest -> openclaw gateway install --force -> openclaw gateway restart.",
94+
);
8995
}
9096

9197
if (

0 commit comments

Comments
 (0)