HKUDS/DeepTutor · error · ValueError
invalid cron expression {schedule.expr!r}: {exc}
Error message
invalid cron expression {schedule.expr!r}: {exc} What it means
compute_next_run wraps croniter evaluation in a broad except and re-raises any parsing/evaluation failure as ValueError including the offending expression and underlying cause. Invalid or unsupportable cron strings fail fast at validation time rather than at fire time.
Source
Thrown at deeptutor/services/cron/service.py:146
return now_ms + schedule.every_seconds * 1000
if schedule.kind == "cron" and schedule.expr:
try:
from zoneinfo import ZoneInfo
from croniter import croniter
tz = ZoneInfo(schedule.tz) if schedule.tz else datetime.now().astimezone().tzinfo
base = datetime.fromtimestamp(now_ms / 1000, tz=tz)
next_dt = croniter(schedule.expr, base).get_next(datetime)
return int(next_dt.timestamp() * 1000)
except ImportError:
raise ValueError(
"cron expressions need the 'croniter' package — "
"use an 'every' or 'at' schedule instead"
) from None
except Exception as exc:
raise ValueError(f"invalid cron expression {schedule.expr!r}: {exc}") from None
return None
def validate_schedule(schedule: CronSchedule) -> None:
"""Reject schedules that could never run (raises ValueError)."""
if schedule.kind == "at":
if not schedule.at_ms:
raise ValueError("'at' schedules need a time")
if schedule.at_ms <= _now_ms():
raise ValueError("'at' time is in the past")
return
if schedule.kind == "every":
if not schedule.every_seconds or schedule.every_seconds < 30:
raise ValueError("'every' interval must be at least 30 seconds")
return
if schedule.kind == "cron":
if schedule.tz:View on GitHub (pinned to 3e82f13042)
Solutions
- Fix the expression to standard 5-field cron syntax (minute hour day month weekday)
- Validate user input with croniter.croniter(expr, datetime.now()) before calling add_job
- Log schedule.expr on failure to identify which job config is broken
Example fix
# before
expr = "0 9 * * *" + user_input # concatenated garbage
job = svc.add_job(CronSchedule(kind="cron", expr=expr), ...)
# after
from croniter import croniter
try:
croniter(user_input, datetime.now())
expr = user_input
except Exception:
expr = "0 9 * * *"
job = svc.add_job(CronSchedule(kind="cron", expr=expr), ...) Defensive patterns
Strategy: validation
Validate before calling
from datetime import datetime
from croniter import croniter
def valid_cron(expr: str) -> bool:
try:
croniter(expr, datetime.now())
return True
except Exception:
return False
assert valid_cron(schedule.expr), f"bad cron: {schedule.expr!r}" Try / catch
try:
svc.add_job(schedule, ...)
except ValueError as e:
if "invalid cron expression" in str(e):
log.warning("rejecting cron %r", schedule.expr)
return error_response(str(e))
raise Prevention
- Validate cron strings at the API boundary with croniter
- Never concatenate/build cron strings from unvalidated parts
- Fuzz-test generated expressions in CI
When it happens
Trigger: Passing a malformed expression like CronSchedule(kind="cron", expr="99 * * *") or "* * *" (wrong field count) to add_job or validate_schedule.
Common situations: Typos in hand-written cron strings; converting 5-field to 6-field/Quartz syntax; unsanitized user-supplied cron input from forms or chat commands.
Related errors
- 'every' interval must be at least 30 seconds
- cron expressions need the 'croniter' package — use an 'every
- 'at' schedules need a time
- 'at' time is in the past
- unknown timezone {schedule.tz!r}
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/bec021ed12de62c9.
Report an issue: GitHub.