openclaw - ✅(Solved) Fix cron: --session-key silently ignored for isolated agentTurn jobs [1 pull requests, 1 participants]

Official PRs (…)
ON THIS PAGE

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#63442Fetched 2026-04-09 07:53:40
View on GitHub
Comments
0
Participants
1
Timeline
3
Reactions
0
Author
Participants
Timeline (top)
referenced ×2cross-referenced ×1

openclaw cron add --session-key <key> (and cron edit --session-key) is accepted by the CLI and reflected back in cron list, but the gateway ignores it when the job runs. Every cron run is keyed under agent:<agentId>:cron:<jobId> regardless, and each run also creates a persistent :run:<sessionId> receipt entry that the in-process cron.sessionRetention reaper does not clean up.

Net effect: there is no way to make multiple cron runs share a session via CLI flags, and the session store grows unbounded without an externally configured session.maintenance policy.

Error Message

  1. Reject --session-key at the CLI layer for incompatible sessionTarget values, with a clear error, so users aren't misled by the silent acceptance.

Root Cause

openclaw cron add --session-key <key> (and cron edit --session-key) is accepted by the CLI and reflected back in cron list, but the gateway ignores it when the job runs. Every cron run is keyed under agent:<agentId>:cron:<jobId> regardless, and each run also creates a persistent :run:<sessionId> receipt entry that the in-process cron.sessionRetention reaper does not clean up.

Net effect: there is no way to make multiple cron runs share a session via CLI flags, and the session store grows unbounded without an externally configured session.maintenance policy.

Fix Action

Fix / Workaround

  1. Make heartbeat checks share context across runs (would meaningfully reduce token cost on long-running deployments).
  2. Rely on cron.sessionRetention to bound store growth — must configure top-level session.maintenance.pruneAfter as a workaround.

Workaround for affected deployments: set top-level session.maintenance (session singular, NOT tools.sessions):

PR fix notes

PR #63448: fix(cron): honor --session-key for isolated agentTurn jobs

Description (problem / solution / changelog)

Summary

Fixes #63442 — cron: --session-key silently ignored for isolated agentTurn jobs.

Root Cause

In server-cron.ts, runIsolatedAgentJob hardcoded the session key to cron:<jobId> and only checked job.sessionTarget for session: prefixes. The user-supplied job.sessionKey (set via --session-key CLI flag) was accepted, persisted, and displayed by cron list, but never wired into isolated job execution.

Fix

Changed session key resolution in runIsolatedAgentJob to a 3-tier priority:

  1. sessionTarget starting with session: — explicit session target (unchanged)
  2. job.sessionKey — user-supplied key via --session-key (NEW — was silently dropped)
  3. cron:<jobId> — auto-generated fallback (unchanged, backward-compatible default)

This is a 6-line change in server-cron.ts. The downstream runCronIsolatedAgentTurn already handles custom session keys correctly (line 224 of run.ts uses params.sessionKey when provided).

Tests

Added 2 regression tests to server-cron.test.ts:

  • honors job.sessionKey for isolated agentTurn jobs (#63442) — confirms user-supplied key flows through
  • falls back to cron:<id> when no sessionKey is set — confirms backward compatibility

All 5 tests in the file pass. Existing run.session-key.test.ts (8 tests) unaffected.

Changed files

  • src/gateway/server-cron.test.ts (modified, +66/-0)
  • src/gateway/server-cron.ts (modified, +5/-1)

Code Example

# 1. Create a cron with an explicit --session-key
openclaw cron add \
  --agent main \
  --name "session-key test" \
  --cron "0 0 1 1 *" --tz "America/Denver" \
  --session-key "agent:main:my-shared-key" \
  --message "Reply OK only." \
  --no-deliver --json
# → returns: { "id": "<JOB_ID>", "sessionKey": "agent:main:my-shared-key", "sessionTarget": "isolated", ... }

# 2. Trigger it twice
openclaw cron run <JOB_ID> --expect-final --timeout 60000
openclaw cron run <JOB_ID> --expect-final --timeout 60000

# 3. Inspect the session store
openclaw sessions --json

---

agent:main:cron:<JOB_ID>                              ← mutable pointer, rebound to latest sessionId on each run
agent:main:cron:<JOB_ID>:run:<sessionId-of-run-1>     ← persistent receipt
agent:main:cron:<JOB_ID>:run:<sessionId-of-run-2>     ← persistent receipt

---

{
  "session": {
    "maintenance": {
      "mode": "enforce",
      "pruneAfter": "14d",
      "maxEntries": 400,
      "maxDiskBytes": "500mb"
    }
  }
}
RAW_BUFFERClick to expand / collapse

Summary

openclaw cron add --session-key <key> (and cron edit --session-key) is accepted by the CLI and reflected back in cron list, but the gateway ignores it when the job runs. Every cron run is keyed under agent:<agentId>:cron:<jobId> regardless, and each run also creates a persistent :run:<sessionId> receipt entry that the in-process cron.sessionRetention reaper does not clean up.

Net effect: there is no way to make multiple cron runs share a session via CLI flags, and the session store grows unbounded without an externally configured session.maintenance policy.

Version

OpenClaw 2026.4.5 (commit 3e72c03), Linuxbrew install on Linux 6.8.0, bundled Node runtime.

Reproduction

# 1. Create a cron with an explicit --session-key
openclaw cron add \
  --agent main \
  --name "session-key test" \
  --cron "0 0 1 1 *" --tz "America/Denver" \
  --session-key "agent:main:my-shared-key" \
  --message "Reply OK only." \
  --no-deliver --json
# → returns: { "id": "<JOB_ID>", "sessionKey": "agent:main:my-shared-key", "sessionTarget": "isolated", ... }

# 2. Trigger it twice
openclaw cron run <JOB_ID> --expect-final --timeout 60000
openclaw cron run <JOB_ID> --expect-final --timeout 60000

# 3. Inspect the session store
openclaw sessions --json

Expected

Both runs append to a single persistent session keyed agent:main:my-shared-key. Session count grows by 1 (the shared session) regardless of how many times the cron fires.

Actual

Three new entries in the session store after two runs:

agent:main:cron:<JOB_ID>                              ← mutable pointer, rebound to latest sessionId on each run
agent:main:cron:<JOB_ID>:run:<sessionId-of-run-1>     ← persistent receipt
agent:main:cron:<JOB_ID>:run:<sessionId-of-run-2>     ← persistent receipt
  • agent:main:my-shared-key is never created.
  • Each run gets a brand-new sessionId UUID — runs do not share context.
  • The :run: entries persist indefinitely. The in-process cron.sessionRetention reaper (default 24h) does not sweep them — verified by finding 21–28 day old :run: entries on a production deployment with no external maintenance configured. Tested with sessionTarget: isolated. sessionTarget: main is a different code path (requires --system-event instead of --message) and was not exercised in this reproduction.

Impact

On a deployment running two heartbeat-style crons at 15,45 7-20 * * 1-5 and 0,30 8-18 * * 1-5, the session store accumulated 179 entries across 3 agents with cron :run: receipts going back 28 days. Operators have no way to:

  1. Make heartbeat checks share context across runs (would meaningfully reduce token cost on long-running deployments).
  2. Rely on cron.sessionRetention to bound store growth — must configure top-level session.maintenance.pruneAfter as a workaround.

Adding session.maintenance cleared 53 stale entries on the first enforce pass, confirming the in-process reaper had been silently failing.

Suggested fixes (any one would resolve)

  1. Honor --session-key for sessionTarget: isolated agentTurn jobs — route runs to the user-provided key, append turns to that session.
  2. Reject --session-key at the CLI layer for incompatible sessionTarget values, with a clear error, so users aren't misled by the silent acceptance.
  3. Fix cron.sessionRetention to actually sweep :run: receipts (it appears to only handle cleanly-completed sessions, not aborted/timed-out ones).
  4. Add a documented sessionMode: shared option that explicitly opts into cross-run session reuse.

Fix #2 is the minimum viable correction — current behavior is the worst case (silently misleading). Fix #1 or #4 would unlock real architectural improvements for high-frequency cron deployments.

Related

Workaround for affected deployments: set top-level session.maintenance (session singular, NOT tools.sessions):

{
  "session": {
    "maintenance": {
      "mode": "enforce",
      "pruneAfter": "14d",
      "maxEntries": 400,
      "maxDiskBytes": "500mb"
    }
  }
}

The schema docs at runtime-schema-CZl4UsDY.js:17650+ describe this block but it is not present in default configs and openclaw doctor --fix does not add it.

extent analysis

TL;DR

The most likely fix is to honor the --session-key flag for sessionTarget: isolated agentTurn jobs, routing runs to the user-provided key and appending turns to that session.

Guidance

  • Verify that the --session-key flag is being silently accepted by the CLI but ignored by the gateway, causing the session store to grow unbounded.
  • Check the session.maintenance configuration to ensure it is set up to prune stale entries, as the in-process cron.sessionRetention reaper appears to be failing.
  • Consider adding a sessionMode: shared option to explicitly opt into cross-run session reuse, or reject --session-key at the CLI layer for incompatible sessionTarget values.
  • To mitigate the issue, set up a top-level session.maintenance policy with a reasonable pruneAfter value, such as 14 days, to bound store growth.

Example

To set up a top-level session.maintenance policy, add the following configuration:

{
  "session": {
    "maintenance": {
      "mode": "enforce",
      "pruneAfter": "14d",
      "maxEntries": 400,
      "maxDiskBytes": "500mb"
    }
  }
}

Notes

The cron.sessionRetention reaper appears to only handle cleanly-completed sessions, not aborted or timed-out ones, which may be contributing to the issue. Additionally, the sessionTarget: main code path is not exercised in the reproduction and may require different handling.

Recommendation

Apply the workaround by setting up a top-level session.maintenance policy, as this will help bound store growth and mitigate the issue until a more permanent fix can be implemented.

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