fix(cron): guard against None values in legacy job entries for cron list#23490
Closed
mtvgadgets wants to merge 1 commit into
Closed
fix(cron): guard against None values in legacy job entries for cron list#23490mtvgadgets wants to merge 1 commit into
cron list#23490mtvgadgets wants to merge 1 commit into
Conversation
…list`
`hermes cron list` raised AttributeError on any installation with cron jobs
created on older versions, because two field shapes evolved:
1. `repeat` was stored as `None` in older jobs but as `{"times": null,
"completed": 0}` in newer ones. `job.get("repeat", {})` returns `None`
when the key exists with value `None`, so the subsequent
`.get("times")` blew up with `AttributeError: 'NoneType' object has no
attribute 'get'`.
2. The schedule fallback chain referenced `schedule.value`, but the
serialized field is `schedule.expr`. Newer jobs include a top-level
`schedule_display` so the bug was masked there, but legacy jobs (no
`schedule_display`) fell through to the missing `value` key and
rendered as `Schedule: ?`.
Both fixes are defensive: use `or {}` and add `expr` to the fallback
chain ahead of `value` to preserve compatibility with any historical
field naming.
Reproduction (any installation with cron jobs predating the
`repeat`/`schedule_display` schema change):
$ hermes cron list
Traceback (most recent call last):
File ".../hermes_cli/main.py", line 10926, in main
args.func(args)
File ".../hermes_cli/cron.py", line 276, in cron_command
cron_list(show_all)
File ".../hermes_cli/cron.py", line 66, in cron_list
repeat_times = repeat_info.get("times")
AttributeError: 'NoneType' object has no attribute 'get'
This was referenced May 19, 2026
Open
19 tasks
Contributor
|
This appears to be implemented on current Evidence:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
hermes cron listraisesAttributeError: 'NoneType' object has no attribute 'get'on any installation that has cron jobs predating the currentrepeatschema. A secondary cosmetic bug also displaysSchedule: ?for those same legacy jobs because the schedule fallback references the wrong field name.This PR fixes both with defensive
or {}/ fallback chain inhermes_cli/cron.py.Reproduction
Any installation with cron jobs created on an older version (where
repeatwas serialized asnullrather than{"times": null, "completed": 0}):Sample
~/.hermes/cron/jobs.jsonthat triggers the bug:{ "jobs": [ { "id": "74bd2f6d0bce", "name": "Market Screener", "schedule": {"kind": "cron", "expr": "0 11,13,15 * * 1-5"}, "repeat": null, ... } ] }(Compare to newer jobs created via
hermes cron create, which emit"repeat": {"times": null, "completed": 0}and a top-level"schedule_display".)Root cause
Two distinct issues in the same
for job in jobsblock:1.
repeat: null→AttributeErrordict.get(key, default)returns the default only when the key is missing. When the key exists with valueNone, it returnsNone. Older jobs that serialized"repeat": nulltherefore bypass the default.2. Schedule fallback references nonexistent
valuefieldThe serialized field is
schedule.expr, notschedule.value. Newer jobs include a top-levelschedule_displaythat masks this, but legacy jobs (withoutschedule_display) fall through to the missingvalueand render asSchedule: ?.Fix
Two surgical changes, fully backwards compatible:
or {}handles both missing key andNonevalue uniformly.expr(current field name) ahead ofvalue(preserves legacy compatibility if any installation ever stored that shape).Testing
Verified on a real installation with mixed-vintage jobs:
Before:
After:
Both legacy
repeat: nulljobs and newerrepeat: {...}jobs render correctly with their schedule strings.Notes
repeat: null/repeat: {...}shape divergence is pre-existing and out of scope. A future migration pass could normalize on read, but defensive parsing is a faster and safer fix for the immediate UX regression.