HKUDS/DeepTutor · error · ValueError
'at' time is in the past
Error message
'at' time is in the past
What it means
validate_schedule rejects one-shot 'at' schedules whose at_ms is <= the current epoch milliseconds. A past-dated job can never fire, so it is rejected up front using the server's clock (_now_ms()).
Source
Thrown at deeptutor/services/cron/service.py:157
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:
try:
from zoneinfo import ZoneInfo
ZoneInfo(schedule.tz)
except Exception:
raise ValueError(f"unknown timezone {schedule.tz!r}") from None
# Raises ValueError on bad/unsupported expressions.
if compute_next_run(schedule, _now_ms()) is None:
raise ValueError(f"cron expression {schedule.expr!r} never fires")
return
raise ValueError(f"unknown schedule kind {schedule.kind!r}")View on GitHub (pinned to 3e82f13042)
Solutions
- Recompute at_ms from server time right before calling add_job (now + delta)
- Add a buffer (e.g. +60s) to user-chosen times to absorb latency and clock skew
- Sync system clocks (NTP) on hosts that generate at_ms
Example fix
# before at_ms = user_selected_epoch_ms # may already be past svc.add_job(CronSchedule(kind="at", at_ms=at_ms), ...) # after import time now = int(time.time() * 1000) at_ms = max(user_selected_epoch_ms, now + 60_000) svc.add_job(CronSchedule(kind="at", at_ms=at_ms), ...)
Defensive patterns
Strategy: validation
Validate before calling
import time
def at_in_future(s: CronSchedule, skew_ms: int = 60_000) -> bool:
return bool(s.at_ms) and s.at_ms > int(time.time() * 1000) + skew_ms Try / catch
try:
svc.add_job(schedule, ...)
except ValueError as e:
if "in the past" in str(e):
schedule.at_ms = int((time.time() + 3600) * 1000) # reschedule +1h
svc.add_job(schedule, ...)
else:
raise Prevention
- Stamp at_ms immediately before submission, not long before
- Add a safety buffer to user-selected times
- Keep clocks NTP-synced
When it happens
Trigger: Passing at_ms in the past (or exactly now) to add_job; a delay between computing at_ms and submission letting the target time pass; server clock skew.
Common situations: Client computes the timestamp with an out-of-sync clock; retrying an old request payload after the target time passed; timezone/unit confusion producing a past ms value.
Related errors
- 'at' schedules need a time
- invalid cron expression {schedule.expr!r}: {exc}
- 'every' interval must be at least 30 seconds
- unknown timezone {schedule.tz!r}
- cron expression {schedule.expr!r} never fires
AI-assisted analysis of HKUDS/DeepTutor@3e82f13042 (2026-08-27).
Data as JSON: /api/errors/cc9b538c4e5c60c5.
Report an issue: GitHub.