Bug
In cron/jobs.py, get_due_jobs() uses _recoverable_oneshot_run_at() to recover jobs with null next_run_at. This function only handles one-shot jobs — for recurring cron/interval jobs, it returns None, causing the job to be silently skipped via continue.
Any recurring cron job that ends up with next_run_at: null (after updates, restarts, or manual edits to jobs.json) will never fire again until the user manually sets next_run_at.
Reproduction
- Create a recurring cron job (e.g.
0 21 * * 0-4)
- Set its
next_run_at to null in jobs.json (or trigger it via restart/update)
- The job silently stops firing — no error, no warning
Expected behavior
For recurring cron/interval jobs with null next_run_at, compute_next_run() should be called to recompute the next run time instead of falling through to the one-shot recovery path.
Suggested fix
next_run = job.get("next_run_at")
if not next_run:
schedule = job.get("schedule", {})
kind = schedule.get("kind")
if kind in ("cron", "interval"):
recovered_next = compute_next_run(schedule, now.isoformat())
else:
recovered_next = _recoverable_oneshot_run_at(
schedule, now, last_run_at=job.get("last_run_at"),
)
if not recovered_next:
continue
...
Environment
- Hermes Agent v0.7.0+
cron/jobs.py, get_due_jobs() function around line 668
Bug
In
cron/jobs.py,get_due_jobs()uses_recoverable_oneshot_run_at()to recover jobs with nullnext_run_at. This function only handles one-shot jobs — for recurring cron/interval jobs, it returnsNone, causing the job to be silently skipped viacontinue.Any recurring cron job that ends up with
next_run_at: null(after updates, restarts, or manual edits tojobs.json) will never fire again until the user manually setsnext_run_at.Reproduction
0 21 * * 0-4)next_run_attonullinjobs.json(or trigger it via restart/update)Expected behavior
For recurring
cron/intervaljobs with nullnext_run_at,compute_next_run()should be called to recompute the next run time instead of falling through to the one-shot recovery path.Suggested fix
Environment
cron/jobs.py,get_due_jobs()function around line 668