You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
npm global (~/.npm-global/lib/node_modules/openclaw),
systemd user service (systemctl --user).
Summary
After upgrading to 2026.4.2, the gateway silently reports jobCount: 0 at startup despite ~/.openclaw/cron/jobs.json containing 37 valid, working cron jobs. The jobs are valid JSON, parse correctly, and were fully operational on the prior version. On first cron add or job write, only the new job is persisted — all 37 existing jobs are permanently lost.
Steps to reproduce
Run a working OpenClaw instance on 2026.3.x with persisted cron jobs in ~/.openclaw/cron/jobs.json (plain JSON array format: [{job}, {job}, ...]).
Upgrade to 2026.4.2.
Restart the gateway.
Observe cron list returns 0 jobs.
Run cron add to create a test job.
Observe the file is rewritten with only the new job — all previous jobs are gone.
Expected behavior
The loader reads existing valid JSON arrays and loads all jobs, or
If a format migration is required, it migrates the old format and warns, or
At minimum, the loader logs an ERROR explaining why it rejects the file.
Actual behavior
Gateway logs show exactly:
{"module":"cron","storePath":"/home/moltbot/.openclaw/cron/jobs.json"}
{"jobCount":0,"enabledCount":0,"withNextRun":0}
"cron: armTimer skipped - no jobs with nextRunAtMs""cron: started"
Zero jobCount, zero warnings, zero errors. The file is valid JSON but silently skipped. The first subsequent write clobbers the file: it creates a new { "version": 1, "jobs": [...] } envelope containing only the newly-added job, destroying all pre-existing entries.
{"module":"cron","storePath":"/home/moltbot/.openclaw/cron/jobs.json"}
{"jobCount":0,"enabledCount":0,"withNextRun":0}
"cron: armTimer skipped - no jobs with nextRunAtMs"
"cron: started"
Before write — file is valid plain array with 37 items:
After cron add — file overwritten with single job in new versioned format:
{
"version": 1,
"jobs": [{ /* only the newly-added test job */ }]
}
The add call itself succeeds (returns a valid job ID), but the write path ignores the pre-existing 37 jobs and replaces them.
Root cause analysis
The 2026.4.2 cron loader appears to have changed the store format from a plain JSON array ([{job}, ...]) to a versioned envelope ({ "version": 1, "jobs": [{job}, ...] }). The loader:
Does not recognize or migrate the old plain-array format.
Does not log an error or warning when it fails to parse the file.
Reports jobCount: 0 silently, making operators believe there were never jobs.
Writes the new versioned format on first mutation, silently clobbering all old data.
Impact
Data loss is automatic and irreversible: the first write after startup permanently destroys all pre-migration jobs. With 37 jobs in my case, all scheduling, delivery config, failure alerts, and job history are lost.
openclaw doctor --fix does not detect or migrate the issue.
This is the third distinct report of cron jobs being silently lost (see Related issues).
Related issues
#52569 — "Cron jobs silently lost after upgrading 2026.3.12 → 2026.3.13" (same symptom, older version)
#53746 — "saveCronStore overwrites jobs.json from partial in-memory state after restart" (same destructive-write pattern)
#60334 — "2026.4.2 update rejects legacy config keys and cron jobs.json may require manual backup restore" (same version, though reporter had malformed JSON)
#33451 — "legacy cron jobs with string schedule + top-level command are not migrated on load" (related migration gap)
None of the above have been resolved. This report adds the specific v2026.4.2 format-change migration gap with full evidence and repro.
Proposed fix
Backward-compatible loader: The cron store loader should detect both formats (plain array and versioned envelope) and load them transparently.
Graceful migration: If the file is a plain array, wrap it in { "version": 1, "jobs": [...] } on the next write.
Explicit error logging: If the file cannot be parsed, log a WARN or ERROR with the first 200 characters so operators can diagnose instead of seeing silent zero-count failures.
Bug type
Regression (worked before, now fails) / Data Loss
OpenClaw version
OpenClaw 2026.4.2 (d74a122)
OS and install method
~/.npm-global/lib/node_modules/openclaw),systemctl --user).Summary
After upgrading to 2026.4.2, the gateway silently reports
jobCount: 0at startup despite~/.openclaw/cron/jobs.jsoncontaining 37 valid, working cron jobs. The jobs are valid JSON, parse correctly, and were fully operational on the prior version. On firstcron addor job write, only the new job is persisted — all 37 existing jobs are permanently lost.Steps to reproduce
~/.openclaw/cron/jobs.json(plain JSON array format:[{job}, {job}, ...]).cron listreturns 0 jobs.cron addto create a test job.Expected behavior
Actual behavior
Gateway logs show exactly:
{"module":"cron","storePath":"/home/moltbot/.openclaw/cron/jobs.json"} {"jobCount":0,"enabledCount":0,"withNextRun":0} "cron: armTimer skipped - no jobs with nextRunAtMs" "cron: started"Zero
jobCount, zero warnings, zero errors. The file is valid JSON but silently skipped. The first subsequent write clobbers the file: it creates a new{ "version": 1, "jobs": [...] }envelope containing only the newly-added job, destroying all pre-existing entries.Logs and evidence
Gateway startup log —
jobCount: 0despite valid file:Before write — file is valid plain array with 37 items:
After
cron add— file overwritten with single job in new versioned format:{ "version": 1, "jobs": [{ /* only the newly-added test job */ }] }The
addcall itself succeeds (returns a valid job ID), but the write path ignores the pre-existing 37 jobs and replaces them.Root cause analysis
The 2026.4.2 cron loader appears to have changed the store format from a plain JSON array (
[{job}, ...]) to a versioned envelope ({ "version": 1, "jobs": [{job}, ...] }). The loader:jobCount: 0silently, making operators believe there were never jobs.Impact
openclaw doctor --fixdoes not detect or migrate the issue.Related issues
None of the above have been resolved. This report adds the specific v2026.4.2 format-change migration gap with full evidence and repro.
Proposed fix
{ "version": 1, "jobs": [...] }on the next write.saveCronStoreoverwrites jobs.json from partial in-memory state after restart, causing silent job loss #53746 for details).