Summary
A cron job can complete successfully (lastStatus: "ok") but retain a stale runningAtMs timestamp in its state. This causes cron.run (manual trigger) to return {"ran": false, "reason": "already-running"} and prevents the job from being triggered again until the field is manually removed from jobs.json.
Steps to reproduce
- Have a cron job running on an every schedule (e.g. everyMs: 3600000)
- The job completes successfully — lastStatus: "ok", consecutiveErrors: 0
- Attempt to manually trigger via cron.run RPC or control UI
- Blocked with already-running because state.runningAtMs was never cleared
Expected behavior
runningAtMs should always be cleared on completion. Suggest adding a staleness check (e.g. if runningAtMs older than 2 × timeoutSeconds, treat as stale).
Actual behavior
{
"lastRunAtMs": 1771179192872,
"lastStatus": "ok",
"consecutiveErrors": 0,
"runningAtMs": 1771182792873
}
Workaround: Manually remove runningAtMs from ~/.openclaw/cron/jobs.json.
OpenClaw version
2026.2.13
Operating system
macOS 26.2 Apple Silicon
Install method
npm global
Logs, screenshots, and evidence
Impact and severity
No response
Additional information
No response
Summary
A cron job can complete successfully (lastStatus: "ok") but retain a stale runningAtMs timestamp in its state. This causes cron.run (manual trigger) to return {"ran": false, "reason": "already-running"} and prevents the job from being triggered again until the field is manually removed from jobs.json.
Steps to reproduce
Expected behavior
runningAtMsshould always be cleared on completion. Suggest adding a staleness check (e.g. if runningAtMs older than 2 × timeoutSeconds, treat as stale).Actual behavior
Workaround: Manually remove runningAtMs from ~/.openclaw/cron/jobs.json.
OpenClaw version
2026.2.13
Operating system
macOS 26.2 Apple Silicon
Install method
npm global
Logs, screenshots, and evidence
Impact and severity
No response
Additional information
No response