fix(scheduler): fail closed on malformed scheduled_time instead of 500 (#1410)

compute_next_run parsed scheduled_time as "HH:MM" with int(parts[0]),
int(parts[1]) and no validation, so "9", "9am", "25:00", "9:" or ":30" raised
IndexError/ValueError. The POST /tasks create route passes the user/LLM-supplied
scheduled_time before its try block (and only validates the cron field), so a
bad value surfaced as an unhandled 500 rather than the clean 400 used for other
invalid fields — and the same crash could fire inside the scheduler loop when
recomputing next_run for an already-stored bad row.

Guard the parse and fail closed (warn + return None), matching the existing
invalid-cron handling in the same function.

Adds tests/test_scheduler_scheduled_time_validation.py — malformed values return
None (fail before with IndexError/ValueError), valid HH:MM still computes.
This commit is contained in:
Shaw
2026-06-03 01:12:07 -04:00
committed by GitHub
parent d38fb4bc46
commit 63aa15d155
2 changed files with 37 additions and 2 deletions
+11 -2
View File
@@ -122,9 +122,18 @@ def compute_next_run(schedule: str, scheduled_time: str,
if not scheduled_time:
return None
# Parse HH:MM
# Parse HH:MM — fail closed on malformed input (no colon, non-numeric,
# out-of-range) the same way an invalid cron expression does above, so a
# bad value like "9" or "9am" returns None instead of raising IndexError/
# ValueError out of the create route (a 500) or the scheduler loop.
parts = scheduled_time.split(":")
hour, minute = int(parts[0]), int(parts[1])
try:
hour, minute = int(parts[0]), int(parts[1])
if not (0 <= hour <= 23 and 0 <= minute <= 59):
raise ValueError("hour/minute out of range")
except (ValueError, IndexError):
logger.warning(f"Invalid scheduled_time '{scheduled_time}'")
return None
if schedule == "daily":
candidate = now.replace(hour=hour, minute=minute, second=0, microsecond=0)