openclaw - ✅(Solved) Fix Auto-updater fails because spawned child inherits OPENCLAW_SERVICE_MARKER and the package-update guard refuses [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#78492Fetched 2026-05-07 03:36:19
View on GitHub
Comments
1
Participants
2
Timeline
2
Reactions
2
Author
Timeline (top)
commented ×1cross-referenced ×1

The hourly auto-updater fires correctly but every attempt fails because the spawned child openclaw update --yes inherits OPENCLAW_SERVICE_MARKER / OPENCLAW_SERVICE_KIND from its launchd-managed gateway parent. The package-update guard in update-command.ts then refuses with Package updates cannot run from inside the gateway service process., so the gateway is stuck on whichever version was installed when launchd last (re)started it.

Net effect on macOS / launchd npm installs: update.auto.enabled = true is effectively a no-op once the gateway is running as a launchd service.

Error Message

runAutoUpdateCommand (in src/infra/update-startup.ts) sets only OPENCLAW_AUTO_UPDATE=1 on the spawned child's env override. resolveCommandEnv merges that on top of process.env, which still contains the launchd-injected markers. The guard shouldBlockPackageUpdateFromGatewayServiceEnvisRunningInsideGatewayService then returns true and the child exits with the "Package updates cannot run from inside the gateway service process." error before the install starts.

  • Guard that refuses the update: src/cli/update-cli/update-command.tsisRunningInsideGatewayService (~L580) and shouldBlockPackageUpdateFromGatewayServiceEnv (~L589), invoked at ~L2249 with the "Package updates cannot run from inside the gateway service process." error.
  • Logs: hourly [gateway] auto-update attempt failed in ~/.openclaw/logs/gateway.log; manual openclaw update --yes fails with the guard error from any child of the gateway; env -u … strip succeeds.

Root Cause

The hourly auto-updater fires correctly but every attempt fails because the spawned child openclaw update --yes inherits OPENCLAW_SERVICE_MARKER / OPENCLAW_SERVICE_KIND from its launchd-managed gateway parent. The package-update guard in update-command.ts then refuses with Package updates cannot run from inside the gateway service process., so the gateway is stuck on whichever version was installed when launchd last (re)started it.

Fix Action

Workaround

We've been wrapping the (separate) skills updater with env -u OPENCLAW_SERVICE_MARKER -u OPENCLAW_SERVICE_KIND openclaw update --yes … and running the package update manually that way. That works but the built-in update.auto.enabled flow can't reach it.

PR fix notes

PR #78494: fix(update): strip OPENCLAW_SERVICE_MARKER from auto-update child env

Description (problem / solution / changelog)

Summary

Strip OPENCLAW_SERVICE_MARKER and OPENCLAW_SERVICE_KIND from the spawn env override in runAutoUpdateCommand so the hourly auto-updater can actually install package updates when the gateway runs as a launchd / system service.

Closes #78492.

Why

The launchd plist (and the equivalent service-env path) injects OPENCLAW_SERVICE_MARKER=openclaw + OPENCLAW_SERVICE_KIND=gateway into the gateway's environment so isRunningInsideGatewayService can detect "you are running inside the live gateway" and refuse a manual openclaw update. Good idea — but runAutoUpdateCommand in src/infra/update-startup.ts spawns its openclaw update --yes child without scrubbing those vars. The child inherits them, the guard trips, and every auto-update attempt exits with:

Package updates cannot run from inside the gateway service process.

Net effect on macOS / launchd npm installs: update.auto.enabled = true is effectively a no-op once the gateway is running as a service. The only way to update is env -u OPENCLAW_SERVICE_MARKER -u OPENCLAW_SERVICE_KIND openclaw update --yes by hand.

Fix

resolveCommandEnv already merges process.env with the override and filters undefined entries before spawn, so explicitly setting the markers to undefined in the override is enough — no helper change needed:

env: {
  OPENCLAW_AUTO_UPDATE: "1",
  OPENCLAW_SERVICE_MARKER: undefined,
  OPENCLAW_SERVICE_KIND: undefined,
},

OPENCLAW_AUTO_UPDATE=1 is left in place as a positive signal for any future code that wants to detect this code path explicitly.

Test

Added a regression test in src/infra/update-startup.test.ts that:

  1. Sets OPENCLAW_SERVICE_MARKER=openclaw and OPENCLAW_SERVICE_KIND=gateway on process.env (simulating the launchd-managed gateway).
  2. Runs the default auto-update path.
  3. Asserts the env override passed to runCommandWithTimeout matches:
    { OPENCLAW_AUTO_UPDATE: "1", OPENCLAW_SERVICE_MARKER: undefined, OPENCLAW_SERVICE_KIND: undefined }

The existing "uses current runtime + entrypoint for default auto-update command execution" test still passes because it asserts the env via expect.objectContaining({ OPENCLAW_AUTO_UPDATE: "1" }).

Diff size

2 files, +59 / -0.

Out of scope

This PR only fixes the env leak from runAutoUpdateCommand. It does not change the guard or the marker injection. If we want a positive allow-signal in the guard (e.g., honour OPENCLAW_AUTO_UPDATE=1 even when the marker is somehow still present, as defence-in-depth), happy to follow up — but stripping the markers at the spawn site is the surgical fix and matches the intent of the existing stripGatewayServiceMarkerEnv helper used by sibling code paths in update-command.ts.

Changed files

  • src/infra/update-startup.test.ts (modified, +50/-0)
  • src/infra/update-startup.ts (modified, +9/-0)

Code Example

[gateway] auto-update attempt failed

---

$ openclaw update --dry-run    # reports the new version is available
$ openclaw update --yes
Package updates cannot run from inside the gateway service process.
$ echo $?
1

---

$ env -u OPENCLAW_SERVICE_MARKER -u OPENCLAW_SERVICE_KIND openclaw update --yes
# updates cleanly

---

env: {
  OPENCLAW_AUTO_UPDATE: "1",
  OPENCLAW_SERVICE_MARKER: undefined,
  OPENCLAW_SERVICE_KIND: undefined,
},
RAW_BUFFERClick to expand / collapse

Summary

The hourly auto-updater fires correctly but every attempt fails because the spawned child openclaw update --yes inherits OPENCLAW_SERVICE_MARKER / OPENCLAW_SERVICE_KIND from its launchd-managed gateway parent. The package-update guard in update-command.ts then refuses with Package updates cannot run from inside the gateway service process., so the gateway is stuck on whichever version was installed when launchd last (re)started it.

Net effect on macOS / launchd npm installs: update.auto.enabled = true is effectively a no-op once the gateway is running as a launchd service.

Reproduction

  1. Install OpenClaw via npm globally.
  2. Run as a launchd service (the standard openclaw daemon install path); confirm the plist sets OPENCLAW_SERVICE_MARKER=openclaw and OPENCLAW_SERVICE_KIND=gateway in EnvironmentVariables.
  3. Set update.auto.enabled = true (and any non-zero stable/beta delay) in openclaw.json.
  4. Have a newer published version available. Wait for the rollout window to expire.
  5. Watch ~/.openclaw/logs/gateway.log:
[gateway] auto-update attempt failed
  1. Reproduce manually from inside any process the gateway spawned (or just inherit the same env):
$ openclaw update --dry-run    # reports the new version is available
$ openclaw update --yes
Package updates cannot run from inside the gateway service process.
$ echo $?
1
  1. Strip the markers and the same command succeeds:
$ env -u OPENCLAW_SERVICE_MARKER -u OPENCLAW_SERVICE_KIND openclaw update --yes
# updates cleanly

Expected behavior

The auto-updater's spawned child should be able to perform a package update — that's the entire point of runAutoUpdateCommand. The guard exists to stop a user/operator from running openclaw update from inside the live gateway process, not to block the gateway's own auto-update flow.

Actual behavior

runAutoUpdateCommand (in src/infra/update-startup.ts) sets only OPENCLAW_AUTO_UPDATE=1 on the spawned child's env override. resolveCommandEnv merges that on top of process.env, which still contains the launchd-injected markers. The guard shouldBlockPackageUpdateFromGatewayServiceEnvisRunningInsideGatewayService then returns true and the child exits with the "Package updates cannot run from inside the gateway service process." error before the install starts.

Root cause file pointers

  • Auto-update child spawn: src/infra/update-startup.tsrunAutoUpdateCommand (~L233). Currently passes env: { OPENCLAW_AUTO_UPDATE: "1" } only, so OPENCLAW_SERVICE_MARKER and OPENCLAW_SERVICE_KIND are inherited from the gateway's process env.
  • Guard that refuses the update: src/cli/update-cli/update-command.tsisRunningInsideGatewayService (~L580) and shouldBlockPackageUpdateFromGatewayServiceEnv (~L589), invoked at ~L2249 with the "Package updates cannot run from inside the gateway service process." error.
  • Marker source: src/daemon/service-env.ts (~L415) sets OPENCLAW_SERVICE_MARKER: GATEWAY_SERVICE_MARKER and OPENCLAW_SERVICE_KIND: GATEWAY_SERVICE_KIND in the launchd plist's EnvironmentVariables.
  • Existing helper that already does the right thing for sibling code paths: stripGatewayServiceMarkerEnv in update-command.ts (~L688).

Workaround

We've been wrapping the (separate) skills updater with env -u OPENCLAW_SERVICE_MARKER -u OPENCLAW_SERVICE_KIND openclaw update --yes … and running the package update manually that way. That works but the built-in update.auto.enabled flow can't reach it.

Proposed fix

In runAutoUpdateCommand, drop the markers (and keep the existing positive OPENCLAW_AUTO_UPDATE=1 signal) when constructing the spawn env override. With the current resolveCommandEnv semantics, setting a key to undefined in the override is enough — it gets filtered out before the spawn:

env: {
  OPENCLAW_AUTO_UPDATE: "1",
  OPENCLAW_SERVICE_MARKER: undefined,
  OPENCLAW_SERVICE_KIND: undefined,
},

PR following.

Environment

  • OpenClaw 2026.5.4 → 2026.5.5 (also reproduced on earlier 2026.5.x).
  • macOS, Apple Silicon, npm install via npm i -g openclaw, gateway running as a user launchd agent.
  • Logs: hourly [gateway] auto-update attempt failed in ~/.openclaw/logs/gateway.log; manual openclaw update --yes fails with the guard error from any child of the gateway; env -u … strip succeeds.

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

The auto-updater's spawned child should be able to perform a package update — that's the entire point of runAutoUpdateCommand. The guard exists to stop a user/operator from running openclaw update from inside the live gateway process, not to block the gateway's own auto-update flow.

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 Auto-updater fails because spawned child inherits OPENCLAW_SERVICE_MARKER and the package-update guard refuses [1 pull requests, 1 comments, 2 participants]