Skip to content

fix(cron): handle bare-list jobs.json in load_jobs()#30208

Closed
aim-ma-sourcing wants to merge 1 commit into
NousResearch:mainfrom
aim-ma-sourcing:fix/load-jobs-bare-list-compat
Closed

fix(cron): handle bare-list jobs.json in load_jobs()#30208
aim-ma-sourcing wants to merge 1 commit into
NousResearch:mainfrom
aim-ma-sourcing:fix/load-jobs-bare-list-compat

Conversation

@aim-ma-sourcing

Copy link
Copy Markdown

Problem

load_jobs() in cron/jobs.py assumes jobs.json is always in the canonical dict format {"jobs": [...]}, calling data.get("jobs", []) unconditionally. However, bare list format [...] can appear from:

  • Distribution installsshutil.copytree copies cron/ as-is during _copy_dist_payload()
  • Quick snapshot restoresshutil.copy2 does raw file copy in restore_quick_snapshot()
  • Older hermes versions or manual edits

When jobs.json contains a bare list, every cronjob(action='list') call fails with:

'list' object has no attribute 'get'

This breaks all cron management until the file is manually repaired.

Fix

Add isinstance(data, list) checks to load_jobs() in both the normal parse path and the JSONDecodeError retry path. When a bare list is detected, auto-repair it to the canonical {"jobs": [...]} format via save_jobs().

Note: curator_backup.py already handled both formats (line 424: # accept both that shape and a bare list for forward compat), but the primary load_jobs() did not.

Testing

Verified locally:

  1. Wrote a bare list to jobs.json
  2. Called load_jobs() — returned correct job data
  3. Confirmed jobs.json was auto-repaired to {"jobs": [...]} format
  4. cronjob(action='list') works correctly after repair

load_jobs() assumed jobs.json is always a dict {"jobs": [...]}, but bare
list format [...] can appear from:
- distribution installs (shutil.copytree copies cron/ as-is)
- quick snapshot restores (raw file copy)
- older hermes versions or manual edits

This caused 'list' object has no attribute 'get' on every cronjob(action='list')
call, breaking all cron management until the file was manually fixed.

curator_backup.py already handled both formats (line 424), but the
primary load_jobs() did not. Now load_jobs() detects bare lists and
auto-repairs them to canonical {"jobs": [...]} format on read.
@alt-glitch alt-glitch added type/bug Something isn't working comp/cron Cron scheduler and job management P2 Medium — degraded but workaround exists duplicate This issue or pull request already exists labels May 22, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

Duplicate of #23002 — same fix for load_jobs() crashing on bare-list jobs.json. #23002 is already open with the same auto-migration approach.

@teknium1

Copy link
Copy Markdown
Contributor

Closing in favor of #34840 (merged). The merged load/restore path already honours the legacy bare-list jobs.json shape (_count_cron_jobs handles both {"jobs":[...]} and [...]), and the root cause of silent cron loss (#32164) is fixed there. Thanks!
#34840

@teknium1 teknium1 closed this May 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

comp/cron Cron scheduler and job management duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants