openclaw - ✅(Solved) Fix [Bug]: Cron delivery channel reverts to 'last' after job execution in 4.15 [2 pull requests, 1 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#68760Fetched 2026-04-19 15:07:58
View on GitHub
Comments
0
Participants
1
Timeline
9
Reactions
0
Participants
Timeline (top)
referenced ×4cross-referenced ×2labeled ×2closed ×1

After upgrading to 4.15, cron job delivery channel reverts to last after each execution, even when explicitly set to telegram. First observed after upgrading to 4.15 — unable to confirm if this is a regression introduced in 4.15 or a pre-existing issue.

Root Cause

After upgrading to 4.15, cron job delivery channel reverts to last after each execution, even when explicitly set to telegram. First observed after upgrading to 4.15 — unable to confirm if this is a regression introduced in 4.15 or a pre-existing issue.

Fix Action

Fixed

PR fix notes

PR #68783: fix(cron): preserve delivery config across job executions (#68760)

Description (problem / solution / changelog)

Summary

Fixes #68760 — Cron job delivery channel reverts to last after execution, overwriting the user-configured value (e.g. telegram).

Problem

After a cron job executes, the delivery.channel field in jobs.json can be overwritten from the user-configured value (e.g. "telegram") to "last". The modification timestamp matches the cron execution time, confirming the overwrite occurs during job completion.

Root Cause

The cron job object is passed by reference through the isolated agent execution pipeline. If any in-flight operation triggers a store persist during execution (e.g., a concurrent cron operation or the agent using the cron tool), the mutated delivery config could be written to disk. When the post-execution reload reads from disk, it picks up the corrupted delivery config instead of the original user-configured values.

Fix

Snapshot the job's delivery configuration before execution (via structuredClone) and restore it when applying run outcomes. This makes the delivery config truly immutable across executions, regardless of what happens during the agent turn.

The fix covers all three execution paths:

  • Timer-driven execution (onTimer) — snapshots in runDueJob, restores in applyOutcomeToStoredJob
  • Manual run (cron.run / force) — snapshots in prepareManualRun, restores in finishPreparedManualRun + mergeManualRunSnapshotAfterReload
  • Startup catch-up (missed jobs on restart) — snapshots before execution, restores via applyOutcomeToStoredJob

Tests

Added regression tests in service.delivery-channel-preserved.test.ts verifying:

  • delivery.channel=telegram persists after timer-driven execution
  • delivery.channel=telegram persists after manual cron.run
  • Both in-memory and on-disk state are verified

Changed files

  • src/cron/service.delivery-channel-preserved.test.ts (added, +121/-0)
  • src/cron/service/ops.ts (modified, +16/-0)
  • src/cron/service/timer.ts (modified, +25/-0)

PR #68829: fix(cron): stop persisting "last" as literal delivery channel value

Description (problem / solution / changelog)

Fixes #68760

Summary

The Control UI writes the runtime sentinel "last" as a literal value into jobs.json when saving a cron job with an empty delivery channel field. This causes user-configured channels (e.g. "telegram") to be overwritten.

Root Cause

In ui/src/ui/controllers/cron.ts, the save path uses:

channel: form.deliveryChannel.trim() || "last"

When the form's delivery channel is empty (which happens when the job was created without an explicit channel), this writes "last" as a literal string to the job's delivery.channel field in jobs.json.

"last" is a runtime-only sentinel meaning "use whatever channel was last used in the session." It should never be persisted — the runtime delivery plan resolver (delivery-plan.ts:53) already applies this fallback at execution time when channel is undefined.

The same issue exists in the failure alert channel save path.

Changes

  • ui/src/ui/controllers/cron.ts:666: Changed form.deliveryChannel.trim() || "last" to form.deliveryChannel.trim() || undefined
  • ui/src/ui/controllers/cron.ts:618: Changed form.failureAlertChannel.trim() || CRON_CHANNEL_LAST to form.failureAlertChannel.trim() || undefined

Test Plan

  1. Create a cron job via dashboard with delivery.channel = "telegram"
  2. Save the job — verify jobs.json shows "channel": "telegram"
  3. Edit the job without changing the channel — save again
  4. Verify jobs.json still shows "channel": "telegram", not "channel": "last"
  5. Create a job with no explicit channel — verify jobs.json has no channel field (not "last")
  6. Verify the job still delivers via the "last used" channel at runtime (runtime fallback in delivery-plan.ts)

Changed files

  • CHANGELOG.md (modified, +2/-0)
  • ui/src/ui/controllers/cron.test.ts (modified, +230/-0)
  • ui/src/ui/controllers/cron.ts (modified, +27/-6)

Code Example

jobs.json modification timestamp matches cron execution time exactly (confirmed via ls -la)
Delivery succeeds on the run where channel was manually set to telegram
Next scheduled run uses last, which fails to deliver if session has expired (idle timeout 60 min)
RAW_BUFFERClick to expand / collapse

Bug type

Behavior bug (incorrect output/state without crash)

Beta release blocker

No

Summary

After upgrading to 4.15, cron job delivery channel reverts to last after each execution, even when explicitly set to telegram. First observed after upgrading to 4.15 — unable to confirm if this is a regression introduced in 4.15 or a pre-existing issue.

Steps to reproduce

Set cron job delivery to channel: telegram, to: <user_id> via dashboard Confirm jobs.json shows correct channel: telegram Wait for cron job to execute After execution, check jobs.json — channel has been overwritten to last

Expected behavior

delivery.channel should persist across executions and not be overwritten by the cron runner.

Actual behavior

After each cron job execution, delivery.channel in jobs.json is overwritten to last, reverting the manually configured telegram setting. The jobs.json modification timestamp matches the cron execution time exactly, confirming the overwrite occurs during job completion.

OpenClaw version

2026.4.15 (041266a)

Operating system

rocky linux

Install method

No response

Model

google/gemini-3-flash-preview

Provider / routing chain

google (direct, no proxy)

Additional provider/model setup details

No response

Logs, screenshots, and evidence

jobs.json modification timestamp matches cron execution time exactly (confirmed via ls -la)
Delivery succeeds on the run where channel was manually set to telegram
Next scheduled run uses last, which fails to deliver if session has expired (idle timeout 60 min)

Impact and severity

Affects all cron jobs with announce delivery. Requires manual correction before every execution. On weekdays when user is unavailable, cron results are lost.

Additional information

No response

extent analysis

TL;DR

The cron job delivery channel reverts to "last" after each execution, instead of persisting the manually configured "telegram" setting, likely due to an issue introduced in OpenClaw version 2026.4.15.

Guidance

  • Verify that the jobs.json file is being modified by the cron runner by checking the file's modification timestamp and comparing it to the cron execution time.
  • Check the OpenClaw documentation for any changes in the 2026.4.15 release that may be causing the delivery channel to be overwritten.
  • Test whether the issue persists when using a different delivery channel or a different cron job configuration.
  • Consider implementing a temporary workaround, such as using a script to reset the delivery channel to "telegram" after each cron job execution.

Example

No code snippet is provided as the issue does not imply a specific code-related solution.

Notes

The issue may be specific to the OpenClaw version 2026.4.15, and it is unclear whether this is a regression or a pre-existing issue. Further investigation is needed to determine the root cause.

Recommendation

Apply a workaround, such as using a script to reset the delivery channel to "telegram" after each cron job execution, until a permanent fix is available. This is because the issue is causing significant impact and severity, and a temporary workaround can help mitigate the effects until a more permanent solution is found.

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

delivery.channel should persist across executions and not be overwritten by the cron runner.

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 [Bug]: Cron delivery channel reverts to 'last' after job execution in 4.15 [2 pull requests, 1 participants]