openclaw - ✅(Solved) Fix Plugin runtime self-update writes timestamps to openclaw.json, triggering gateway stop (not restart loop) [1 pull requests, 2 comments, 3 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#49474Fetched 2026-04-08 00:54:54
View on GitHub
Comments
2
Participants
3
Timeline
5
Reactions
0
Timeline (top)
commented ×2subscribed ×2unsubscribed ×1

Root Cause

Same underlying mechanism as #41001:

  1. lossless-claw has its own npm update-check loop running inside the gateway process
  2. When it finds and installs a new version, the plugin installer writes updated timestamps back to openclaw.json:
"plugins": {
  "installs": {
    "lossless-claw": {
      "source": "npm",
      "resolvedAt": "2026-03-17T21:01:05.607Z",   // ← written at runtime
      "installedAt": "2026-03-17T21:01:29.442Z"   // ← written at runtime
    }
  }
}
  1. The reload watcher detects the change, matches plugins → restart rule, sends SIGTERM
  2. Gateway stops — but since this is a mid-session stop (not a startup loop), launchd/the process manager does not restart it automatically in all configurations, leaving the service dead

Fix Action

Workaround

Set gateway.reload.mode = "hot" in openclaw.json. This suppresses the restart trigger, but means plugin updates are silently ignored until manual restart — not ideal for a plugin acting as contextEngine.

PR fix notes

PR #67589: Gateway: ignore plugins.installs timestamp-only paths for reload (#49474)

Description (problem / solution / changelog)

Summary

  • Problem: Runtime plugin installs / self-updates only bump \plugins.installs.*.resolvedAt\ and .installedAt. The reload matcher uses a broad \plugins → restart\ rule, so hybrid mode queued a full gateway restart (SIGTERM), often leaving the service down (#49474).
  • Why it matters: Install bookkeeping is not the same as changing \plugins.entries\ or loading new gateway plugins; timestamp-only churn should not stop the process.
  • What changed: Before building the reload plan, drop diff paths that are only install-record timestamps (still supports dotted plugin ids via suffix matching).
  • What did NOT change: Other \plugins.installs\ field edits (for example \ ersion) still restart under the existing rule.

Change Type

  • Bug fix

Scope

  • Gateway / orchestration

Linked Issue/PR

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

Root Cause

  • Root cause: \plugins\ prefix in \config-reload-plan\ matches all \plugins.*\ paths, including install-metadata timestamps.
  • Missing detection / guardrail: No distinction between managed install metadata and functional plugin config changes.

Regression Test Plan

  • Unit test
  • Target test or file: \src/gateway/config-reload.test.ts\

User-visible / Behavior Changes

Gateway no longer treats timestamp-only updates under \plugins.installs\ as a restart trigger; other install-record changes still can restart.

Security Impact

  • New permissions/capabilities? No
  • Secrets/tokens handling changed? No
  • New/changed network calls? No
  • Command/tool execution surface changed? No
  • Data access scope changed? No

Compatibility / Migration

  • Backward compatible? Yes
  • Config/env changes? No
  • Migration needed? No

Risks and Mitigations

  • Risk: A hypothetical nested field whose path ends with .resolvedAt\ under \plugins.installs\ could be ignored.
    • Mitigation: Install records are flat; only standard timestamp leaves use these names today.

Made with Cursor

Changed files

  • CHANGELOG.md (modified, +1/-0)
  • src/gateway/config-reload-plan.ts (modified, +57/-0)
  • src/gateway/config-reload.test.ts (modified, +180/-3)
  • src/gateway/config-reload.ts (modified, +16/-2)

Code Example

"plugins": {
  "installs": {
    "lossless-claw": {
      "source": "npm",
      "resolvedAt": "2026-03-17T21:01:05.607Z",   // ← written at runtime
      "installedAt": "2026-03-17T21:01:29.442Z"   // ← written at runtime
    }
  }
}

---

[reload] config change detected; evaluating reload
         (meta.lastTouchedAt, plugins.installs.lossless-claw.resolvedAt,
          plugins.installs.lossless-claw.installedAt)
[reload] config change requires gateway restart
[gateway] signal SIGTERM received
RAW_BUFFERClick to expand / collapse

Bug Description

When an npm-installed plugin (e.g. lossless-claw) performs a runtime self-update (checking npm for a newer version and installing it while the gateway is running), it writes new resolvedAt and installedAt timestamps to openclaw.json. This triggers the plugins → restart reload rule, causing the gateway to send itself SIGTERM and stop entirely — without recovering.

This is a runtime variant of #41001. Unlike #41001 (which triggers on every startup → infinite loop), this variant triggers mid-session and results in a silent, unrecoverable stop.

Environment

  • OpenClaw version: 2026.3.13 (note: newer than #41001's reported 2026.3.8, so this path was not fixed by whatever addressed #41001)
  • OS: macOS (darwin)
  • Plugin: @martian-engineering/lossless-claw v0.3.0, installed via npm, configured as contextEngine slot
  • Gateway mode: local

Root Cause

Same underlying mechanism as #41001:

  1. lossless-claw has its own npm update-check loop running inside the gateway process
  2. When it finds and installs a new version, the plugin installer writes updated timestamps back to openclaw.json:
"plugins": {
  "installs": {
    "lossless-claw": {
      "source": "npm",
      "resolvedAt": "2026-03-17T21:01:05.607Z",   // ← written at runtime
      "installedAt": "2026-03-17T21:01:29.442Z"   // ← written at runtime
    }
  }
}
  1. The reload watcher detects the change, matches plugins → restart rule, sends SIGTERM
  2. Gateway stops — but since this is a mid-session stop (not a startup loop), launchd/the process manager does not restart it automatically in all configurations, leaving the service dead

Difference from #41001

#41001This issue
Trigger timingEvery startup (plugin loader resolves on boot)Runtime only (plugin self-update check)
SymptomInfinite restart loop (~70s cycle)Silent mid-session stop, no recovery
Version2026.3.82026.3.13 (still present)
Recoverylaunchd eventually gives upService stays dead until manual restart

Observed Behavior

Gateway runs normally for an extended period, then:

[reload] config change detected; evaluating reload
         (meta.lastTouchedAt, plugins.installs.lossless-claw.resolvedAt,
          plugins.installs.lossless-claw.installedAt)
[reload] config change requires gateway restart
[gateway] signal SIGTERM received

After this, the gateway is down. No automatic recovery.

Expected Behavior

Runtime plugin updates should not trigger a gateway restart/stop. Options:

  1. Preferred: Plugin self-updates should be applied via hot-reload without restarting the gateway process
  2. Acceptable: Timestamp-only writes to plugins.installs.* (no functional config change) should be classified as kind: "none" in reload rules, not kind: "restart"
  3. Minimum: If a restart is truly required, the gateway should perform a graceful rolling restart (start new process, verify healthy, then stop old) rather than SIGTERM → dead

Workaround

Set gateway.reload.mode = "hot" in openclaw.json. This suppresses the restart trigger, but means plugin updates are silently ignored until manual restart — not ideal for a plugin acting as contextEngine.

extent analysis

Fix Plan

To address the issue, we will implement a hot-reload mechanism for plugin updates. This will prevent the gateway from restarting when a plugin is updated.

Step 1: Update openclaw.json Configuration

Add the following configuration to openclaw.json to enable hot-reload:

{
  "gateway": {
    "reload": {
      "mode": "hot"
    }
  }
}

Step 2: Modify Reload Rules

Update the reload rules to classify timestamp-only writes to plugins.installs.* as kind: "none":

// In reload rules configuration
if (change.type === 'plugins' && change.path.startsWith('plugins.installs.')) {
  if (change.data.resolvedAt || change.data.installedAt) {
    return { kind: 'none' };
  }
}

Step 3: Implement Hot-Reload for Plugins

Modify the plugin update mechanism to apply updates via hot-reload without restarting the gateway process:

// In plugin update function
const updatePlugin = async (pluginName) => {
  // Update plugin code here
  // ...
  // Apply update via hot-reload
  await applyHotReload(pluginName);
};

const applyHotReload = async (pluginName) => {
  // Get the updated plugin module
  const updatedModule = await getUpdatedModule(pluginName);
  // Replace the old module with the updated one
  replaceModule(pluginName, updatedModule);
};

Verification

To verify that the fix worked, perform the following steps:

  • Update a plugin using the lossless-claw self-update mechanism.
  • Check the gateway logs to ensure that the plugin update was applied successfully without restarting the gateway.
  • Verify that the gateway remains running and functional after the plugin update.

Extra Tips

To prevent similar issues in the future, consider implementing the following:

  • Regularly review and update reload rules to ensure that they are correctly handling plugin updates.
  • Implement automated testing for plugin updates to catch any issues before they reach production.
  • Consider using a more robust plugin management system that can handle updates and reloads more efficiently.

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…

Still need to ship something?

×6

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

Back to top recommendations

TRENDING