openclaw - 💡(How to fix) Fix Multi-instance gateways with same HOME share cron store and duplicate-fire every job [2 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#69738Fetched 2026-04-22 07:48:55
View on GitHub
Comments
2
Participants
2
Timeline
4
Reactions
0
Author
Timeline (top)
commented ×2mentioned ×1subscribed ×1

When two openclaw-gateway instances run on the same host with the same HOME env var, they both load ~/.openclaw/cron/jobs.json and both fire every scheduled cron tick. OPENCLAW_CONFIG_PATH is honored for the main config file, but resolveConfigDir() derives the cron/state directory from path.dirname(configPath), which collapses to the same ~/.openclaw for both instances.

Result: every cron job fires twice, once per gateway. Each fires with a different agent/bot context, so one run may succeed while the other fails (or both fail), producing the classic "sometimes works, sometimes doesn't" symptom.

Error Message

  1. At minimum, warn on startup if two gateway processes are detected using the same cron store path.

Root Cause

The two runs often produce inconsistent outcomes — e.g., one delivery succeeds (the correct bot for the target chat), the other hits Telegram send failed: chat not found (chat_id=...) because the other gateway's bot isn't in that chat.

Fix Action

Workaround

Add "cron": { "enabled": false } to the subordinate instance's config file. server.impl-BxLfE9ri.js:9066 gates buildGatewayCronService on this flag at boot, which prevents duplicate firing. Downside: the subordinate instance can no longer fire its own crons either.

Code Example

awk -F'"runAtMs":' '{print $2}' ~/.openclaw/cron/runs/c4f6321b-*.jsonl \
  | awk -F',' '{print $1}' | sort | uniq -c | sort -rn | head
   2 1776773208280
   2 1776600000016
   2 1776340800007
   2 1776168000006
   2 1775908800011

---

function resolveDefaultCronDir() {
      return path.join(resolveConfigDir(), "cron");
  }
  function resolveDefaultCronStorePath() {
      return path.join(resolveDefaultCronDir(), "jobs.json");
  }
RAW_BUFFERClick to expand / collapse

Multi-instance gateways with same HOME share cron store and duplicate-fire every job

Summary

When two openclaw-gateway instances run on the same host with the same HOME env var, they both load ~/.openclaw/cron/jobs.json and both fire every scheduled cron tick. OPENCLAW_CONFIG_PATH is honored for the main config file, but resolveConfigDir() derives the cron/state directory from path.dirname(configPath), which collapses to the same ~/.openclaw for both instances.

Result: every cron job fires twice, once per gateway. Each fires with a different agent/bot context, so one run may succeed while the other fails (or both fail), producing the classic "sometimes works, sometimes doesn't" symptom.

Environment

  • macOS (darwin 24.6.0)
  • openclaw installed globally at ~/.npm-global/lib/node_modules/openclaw
  • Two launchd services running side by side: ai.openclaw.gateway (port 18789) and ai.openclaw.sugi (port 18790)
  • Both plists set HOME=/Users/robcolvin
  • Sugi's plist sets OPENCLAW_CONFIG_PATH=/Users/robcolvin/.openclaw/sugi.json

Repro

  1. Start two gateway instances on the same host with the same HOME and distinct OPENCLAW_CONFIG_PATH values pointing to two separate config files in the same parent dir.
  2. Create any cron job on one of them — the job is written to ~/.openclaw/cron/jobs.json.
  3. Wait for the next tick.

Expected

Exactly one finished entry per scheduled tick in ~/.openclaw/cron/runs/<jobId>.jsonl, fired by the instance that created (or owns) the job.

Actual

Two finished entries per tick with the same runAtMs but different sessionIds, delivered by whichever bot/agent each gateway has configured:

awk -F'"runAtMs":' '{print $2}' ~/.openclaw/cron/runs/c4f6321b-*.jsonl \
  | awk -F',' '{print $1}' | sort | uniq -c | sort -rn | head
   2 1776773208280
   2 1776600000016
   2 1776340800007
   2 1776168000006
   2 1775908800011

The two runs often produce inconsistent outcomes — e.g., one delivery succeeds (the correct bot for the target chat), the other hits Telegram send failed: chat not found (chat_id=...) because the other gateway's bot isn't in that chat.

Root cause (traced in dist/)

  • utils-Supr9KvU.js: resolveConfigDir(env, homedir) resolves to path.dirname(env.OPENCLAW_CONFIG_PATH) when that env var is set, otherwise path.join(homeDir, ".openclaw").
  • store-B5g6FEBF.js:9-13:
    function resolveDefaultCronDir() {
        return path.join(resolveConfigDir(), "cron");
    }
    function resolveDefaultCronStorePath() {
        return path.join(resolveDefaultCronDir(), "jobs.json");
    }

Since both instances' OPENCLAW_CONFIG_PATH files live in ~/.openclaw/, path.dirname() collapses them to the same directory and both instances share ~/.openclaw/cron/jobs.json.

Workaround

Add "cron": { "enabled": false } to the subordinate instance's config file. server.impl-BxLfE9ri.js:9066 gates buildGatewayCronService on this flag at boot, which prevents duplicate firing. Downside: the subordinate instance can no longer fire its own crons either.

Suggested fix

Either:

  1. Introduce OPENCLAW_STATE_DIR (or similar) that is independent of OPENCLAW_CONFIG_PATH, so each instance can have its own cron/, memory/, workspace/, sessions/, etc. Document that running multiple gateways on one host requires setting it.
  2. Namespace the cron store path by instance — e.g., derive from OPENCLAW_LAUNCHD_LABEL or the config filename stem (<dir>/cron/<instance>/jobs.json).
  3. At minimum, warn on startup if two gateway processes are detected using the same cron store path.

Happy to test a patch.

extent analysis

TL;DR

To prevent duplicate cron job firings, introduce an OPENCLAW_STATE_DIR environment variable or namespace the cron store path by instance.

Guidance

  • Set the OPENCLAW_STATE_DIR environment variable for each instance to a unique directory, allowing them to have separate cron stores.
  • Alternatively, modify the resolveDefaultCronDir function to namespace the cron store path by instance, using a unique identifier such as the OPENCLAW_LAUNCHD_LABEL or config filename stem.
  • As a temporary workaround, add "cron": { "enabled": false } to the subordinate instance's config file to prevent duplicate firings, although this will also prevent the subordinate instance from firing its own crons.
  • Verify the fix by checking the ~/.openclaw/cron/runs/<jobId>.jsonl files for duplicate entries and ensuring that each instance only fires its own cron jobs.

Example

function resolveDefaultCronDir() {
  const instanceId = process.env.OPENCLAW_LAUNCHD_LABEL;
  return path.join(resolveConfigDir(), "cron", instanceId);
}

Notes

The introduction of OPENCLAW_STATE_DIR or namespacing the cron store path by instance requires modifications to the openclaw-gateway code. The temporary workaround has the downside of preventing the subordinate instance from firing its own crons.

Recommendation

Apply the workaround by adding "cron": { "enabled": false } to the subordinate instance's config file, and then work towards introducing OPENCLAW_STATE_DIR or namespacing the cron store path by instance for a more permanent solution. This is because the workaround provides an immediate fix, while the introduction of OPENCLAW_STATE_DIR or namespacing requires code changes and testing.

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

openclaw - 💡(How to fix) Fix Multi-instance gateways with same HOME share cron store and duplicate-fire every job [2 comments, 2 participants]