-
-
Notifications
You must be signed in to change notification settings - Fork 54.3k
Closed
Labels
bugSomething isn't workingSomething isn't working
Description
Bug Summary
The cron schedule type has a critical bug where missed scheduled runs cause the job to get permanently stuck on a past timestamp, never recovering.
Symptoms
cron statusshowsnextWakeAtMsin the past- Job doesn't run even though it's enabled and shows
okstatus - Restarting the gateway reloads the stale timestamp — doesn't recalculate from current time
Root Cause
The scheduler calculates nextRunAtMs from lastRunAtMs instead of max(lastRunAtMs, currentTime). When runs are missed (gateway down, system asleep), the missed timestamps accumulate and the scheduler never catches up.
Reproduction Steps
- Create a job with
"schedule": {"kind": "cron", "expr": "0 */4 * * *"} - Let it run successfully once (e.g., at midnight)
- Have the gateway miss the next scheduled runs (04:00, 08:00)
- Check
cron status— it showsnextWakeAtMsstill at 04:00 (in the past) - Restart gateway — still stuck on 04:00
Expected Behavior
On startup or when evaluating schedules, the scheduler should check if nextRunAtMs is in the past and recalculate from the current time.
Workaround
Use schedule.kind: "every" instead of "cron":
// ❌ Gets stuck if runs are missed
"schedule": { "kind": "cron", "expr": "0 */4 * * *" }
// ✅ Calculates from current time
"schedule": { "kind": "every", "everyMs": 14400000 }Environment
- OpenClaw version: (gateway restarted today, 2026-02-04)
- OS: macOS Darwin 25.0.0 (arm64)
- Node: v25.5.0
Suggested Fix
In the scheduler logic, when loading jobs or on heartbeat evaluation:
if (job.state.nextRunAtMs < Date.now()) {
// Recalculate next occurrence from now, not from lastRunAtMs
job.state.nextRunAtMs = calculateNextFromCurrentTime(job.schedule);
}This ensures missed runs don't permanently stall the scheduler.
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't working