bytedance/deer-flow · warning · HTTPException

once schedule must be in the future

Error message

once schedule must be in the future

What it means

Raised as HTTP 422 by POST /api/scheduled-tasks when schedule_type is 'once' but compute_next_run_at returned None — the requested run time is not in the future (or could not produce a future occurrence). Once-schedules must resolve to a future instant.

Source

Thrown at backend/app/gateway/routers/scheduled_tasks.py:105

    schedule_spec = dict(body.schedule_spec)
    try:
        validate_timezone(body.timezone)
        if body.schedule_type == "cron":
            raw_cron = schedule_spec.get("cron")
            if not isinstance(raw_cron, str):
                raise HTTPException(status_code=422, detail="cron schedule requires schedule_spec.cron")
            schedule_spec["cron"] = normalize_cron_expression(raw_cron)
        next_run_at = compute_next_run_at(
            body.schedule_type,
            schedule_spec,
            body.timezone,
            now=datetime.now(UTC),
        )
    except ValueError as exc:
        raise HTTPException(status_code=422, detail=str(exc)) from exc

    if body.schedule_type == "once" and next_run_at is None:
        raise HTTPException(status_code=422, detail="once schedule must be in the future")
    if body.schedule_type == "once" and next_run_at is not None and (next_run_at - datetime.now(UTC)).total_seconds() < config.scheduler.min_once_delay_seconds:
        raise HTTPException(
            status_code=422,
            detail=(f"once schedule must be at least {config.scheduler.min_once_delay_seconds} seconds in the future"),
        )

    return await repo.create(
        task_id=f"task-{uuid.uuid4().hex}",
        user_id=str(user.id),
        thread_id=body.thread_id,
        context_mode=body.context_mode,
        assistant_id="lead_agent",
        title=body.title,
        prompt=body.prompt,
        schedule_type=body.schedule_type,
        schedule_spec=schedule_spec,
        timezone=body.timezone,
        next_run_at=next_run_at,

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Set the once run_at to a strictly future instant (server-side UTC is authoritative).
  2. Compute the timestamp at request time rather than reusing a cached value.
  3. Correct significant client/server clock skew (NTP) if the value should be future.

Example fix

// before
{ "schedule_type": "once", "schedule_spec": { "run_at": "2026-01-01T00:00:00Z" } }
// after
const runAt = new Date(Date.now() + 10 * 60_000).toISOString();
{ "schedule_type": "once", "schedule_spec": { "run_at": runAt } }
Defensive patterns

Strategy: validation

Validate before calling

from datetime import datetime, UTC
run_at = datetime.fromisoformat(body["schedule_spec"]["run_at"].replace("Z", "+00:00"))
assert run_at > datetime.now(UTC) + timedelta(seconds=1), "once run_at must be strictly in the future"

Type guard

const isFutureRunAt = (iso: string): boolean =>
  Date.parse(iso) > Date.now();

Prevention

When it happens

Trigger: A once schedule whose run_at is in the past or exactly now, or a spec from which no future time can be computed.

Common situations: Client sends a hardcoded timestamp; clock skew between client and server; user picks 'now' in a datetime picker.

Related errors


AI-assisted analysis of bytedance/deer-flow@1dd6ba1acb (2026-08-14). Data as JSON: /api/errors/9b10ce641547a63c. Report an issue: GitHub.