Skip to content

config.patch unconditionally schedules SIGUSR1 restart, ignoring hot-reload capability #46310

Description

@0xHubert

config.patch unconditionally schedules SIGUSR1 restart, ignoring hot-reload capability

Version: OpenClaw 2026.3.8 (3caab92)
Platform: macOS (LaunchAgent), Node 22

Summary

The config.patch WS API handler unconditionally calls scheduleGatewaySigusr1Restart() after writing the config file, even when the changed paths are fully hot-reloadable. This causes unnecessary gateway restarts (and brief downtime) for config changes that the file watcher's reload planner would handle in-process.

Expected Behavior

When config.patch modifies only hot-reloadable paths (e.g., channel group settings, heartbeat config, cron config), the gateway should apply the change via hot reload without a full process restart — the same way the file watcher handles it when the config file is edited directly.

Actual Behavior

  1. config.patch writes the config file via writeConfigFile()
  2. The file watcher detects the change and successfully hot-reloads it (logged as config hot reload applied or config change applied (dynamic reads: ...))
  3. ~2 seconds later, scheduleGatewaySigusr1Restart() fires unconditionally
  4. On macOS with LaunchAgent, SIGUSR1 triggers launchctl kickstart -k → SIGTERM → full process restart

The hot reload at step 2 already applied the change. The restart at step 3-4 is redundant and kills the gateway.

Reproduction

  1. Run OpenClaw as a LaunchAgent on macOS
  2. Have an agent use the config.patch tool to change a hot-reloadable setting (e.g., a Telegram group's requireMention flag)
  3. Observe logs:
    • config change detected; evaluating reload (...) → hot reload applied ✅
    • ~2-3 seconds later: signal SIGTERM receivedreceived SIGTERM; shutting down 💀

Root Cause

In gateway-cli (around the config.patch handler), after writeConfigFile():

const restart = scheduleGatewaySigusr1Restart({
    delayMs: restartDelayMs,
    reason: "config.patch",
    // ...
});

There is no check against buildGatewayReloadPlan() to determine if the changed paths actually require a restart. The file watcher's reload path does have this classification logic and correctly skips restarts for hot-reloadable changes.

Suggested Fix

Before scheduling the restart in config.patch, run the same reload plan classification that the file watcher uses:

const plan = buildGatewayReloadPlan(changedPaths);
if (!plan.restartGateway) {
    // Let the file watcher handle it via hot reload
    // Skip scheduleGatewaySigusr1Restart()
} else {
    scheduleGatewaySigusr1Restart({ ... });
}

Alternatively, config.patch could skip calling scheduleGatewaySigusr1Restart() entirely and rely on the file watcher (since it already writes the file), though that might miss changes that genuinely require a restart on platforms without file watching.

Impact

  • Every agent-initiated config change causes a full gateway restart (~5-10s downtime)
  • On macOS LaunchAgent, if launchctl bootstrap fails after bootout, the gateway stays dead until manual intervention (openclaw doctor --fix)
  • Makes agent config automation unreliable

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions