HKUDS/Vibe-Trading · error · ValueError
end_at must be in the future
Error message
end_at must be in the future
What it means
The parsed end_at (epoch ms) is not strictly in the future relative to the job creation time. Jobs that would already be expired at creation are rejected as nonsensical.
Solutions
- Set end_at to a future timestamp or omit it for no end
- Sync clocks / use server time when computing end_at from relative offsets
- On retry, regenerate end_at rather than resending the original value
Example fix
// before
{"end_at": 1600000000000}
// after
{"end_at": 3900000000000} // future, or omit Defensive patterns
Strategy: validation
Validate before calling
now_ms = int(time.time() * 1000)
end = draft.get("end_at")
assert end is None or (isinstance(end, int) and not isinstance(end, bool) and end > now_ms) Type guard
def end_at_in_future(v) -> bool:
if v is None or v == "":
return True
if isinstance(v, bool) or not isinstance(v, int):
return False
return v > int(time.time() * 1000) Try / catch
try:
propose_create(draft)
except ValueError as e:
if "end_at must be in the future" in str(e):
draft.pop("end_at", None); retry() Prevention
- Compute end_at at submit time, not at draft-creation time
- Regenerate end_at on retries; keep client clocks NTP-synced
When it happens
Trigger: Passing an end_at in the past (epoch ms or dated string); clock skew between client and server; long-held drafts submitted after their intended end date.
Common situations: Client clocks ahead/behind server; retrying an old draft payload; DST or year typos (e.g. 2025 vs 2026) making the date past.
Related errors
- end_at must be RFC3339 text or epoch milliseconds
- the first scheduled run occurs after end_at
- delivery.mode must be 'in_app', 'origin', or 'configured'
- delivery must be an object
- delivery.target_ref is required for configured delivery
AI-assisted analysis of HKUDS/Vibe-Trading@80ffdda44c (2026-08-28).
Data as JSON: /api/errors/47e9f8b83af7848b.
Report an issue: GitHub.
Appendix: source
Thrown at agent/src/scheduled_research/service.py:165
prompt = playbook.render(variables)
config["playbook"] = playbook_slug
else:
raise ValueError("source.kind must be 'prompt' or 'playbook'")
expression = str(schedule_spec.get("expression") or "").strip()
timezone = schedule_spec.get("timezone")
validate_schedule(expression)
if is_interval_schedule(expression):
validate_timezone_shape(timezone)
else:
validate_timezone(timezone)
next_run_at = now
if timezone is not None and not is_interval_schedule(expression):
next_run_at = next_due(expression, now, timezone)
end_at = _parse_end_at(draft.get("end_at"))
if end_at is not None and end_at <= now:
raise ValueError("end_at must be in the future")
if end_at is not None and next_run_at > end_at:
raise ValueError("the first scheduled run occurs after end_at")
mode = str(delivery_spec.get("mode") or "in_app")
delivery_channel = delivery_target = target_ref = target_label = None
if mode == "configured":
target_ref = str(delivery_spec.get("target_ref") or "").strip()
if not target_ref:
raise ValueError("delivery.target_ref is required for configured delivery")
target = resolve_delivery_target(target_ref)
delivery_channel, delivery_target = target.channel, target.target
target_label = target.label
elif mode == "origin":
delivery_channel, delivery_target, target_ref, target_label = _origin_target(
session_id
)
elif mode != "in_app":
raise ValueError("delivery.mode must be 'in_app', 'origin', or 'configured'")View on GitHub (pinned to 80ffdda44c)