Skip to content

fix(cron): coalesce nullable schedule field to dict in job helpers - #70728

Closed
necoweb3 wants to merge 1 commit into
NousResearch:mainfrom
necoweb3:fix/cron-null-schedule-attribute-error
Closed

fix(cron): coalesce nullable schedule field to dict in job helpers#70728
necoweb3 wants to merge 1 commit into
NousResearch:mainfrom
necoweb3:fix/cron-null-schedule-attribute-error

Conversation

@necoweb3

Copy link
Copy Markdown
Contributor

Summary

Fixes an AttributeError: 'NoneType' object has no attribute 'get' crash when processing cron job records that contain explicit "schedule": null / None values (e.g., from hand-edited jobs.json files or serialized null payloads).

Root Cause

job.get("schedule", {}) only supplies the {} default fallback when the "schedule" key is omitted entirely from the dictionary. When "schedule": null is present, .get() returns None, causing subsequent .get("kind") calls to raise an unhandled AttributeError.

Changes

  1. cron/jobs.py:

    • Replaced job.get("schedule", {}).get(...) with (job.get("schedule") or {}).get(...) across 7 call sites (mark_job_run, claim_dispatch, heartbeat_run_claim, advance_next_run, claim_job_for_fire, get_due_jobs).
    • Coalesced job.get("schedule") to {} before passing to compute_next_run().
  2. hermes_cli/cron.py:

    • Updated cron_list and _job_action to safely resolve schedule and next_run_at on records with nullable fields.
  3. tests/cron/test_jobs.py:

    • Added TestNullScheduleTolerance regression test suite covering mark_job_run, claim_dispatch, advance_next_run, claim_job_for_fire, and get_due_jobs when encountering "schedule": None.

job.get('schedule', {}).get('kind') only supplies {} as default when the 'schedule' key is absent from the job dictionary. If a job is persisted or passed with an explicit 'schedule': null / None (e.g. from JSON deserialization of corrupted/hand-edited jobs or empty API fields), job.get('schedule', {}) evaluates to None and the subsequent .get('kind') call raises AttributeError: 'NoneType' object has no attribute 'get'.

This crash affected 7 call paths in cron/jobs.py (mark_job_run, claim_dispatch, heartbeat_run_claim, advance_next_run, claim_job_for_fire, get_due_jobs) and 2 call paths in hermes_cli/cron.py (cron_list, _job_action).

Fix: replace job.get('schedule', {}).get(...) with (job.get('schedule') or {}).get(...) across all affected sites in cron/jobs.py and hermes_cli/cron.py.

Adds regression test suite TestNullScheduleTolerance in tests/cron/test_jobs.py.
@alt-glitch alt-glitch added type/bug Something isn't working comp/cron Cron scheduler and job management comp/cli CLI entry point, hermes_cli/, setup wizard area/config Config system, migrations, profiles sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades P2 Medium — degraded but workaround exists duplicate This issue or pull request already exists labels Jul 24, 2026
@alt-glitch

Copy link
Copy Markdown
Collaborator

This was generated by AI during triage.

Duplicate of #61758. Its shared non-dict schedule repair covers these direct-call sites, persists the repair, and also covers resume/update paths.

@necoweb3 necoweb3 closed this Jul 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/config Config system, migrations, profiles comp/cli CLI entry point, hermes_cli/, setup wizard comp/cron Cron scheduler and job management duplicate This issue or pull request already exists P2 Medium — degraded but workaround exists sweeper:risk-compatibility Sweeper risk: may break existing users, config, migrations, defaults, or upgrades type/bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants