bytedance/deer-flow · warning · HTTPException

cron schedule requires schedule_spec.cron

Error message

cron schedule requires schedule_spec.cron

What it means

Raised as HTTP 422 by POST /api/scheduled-tasks when schedule_type is 'cron' but schedule_spec.cron is missing or not a string. The cron engine requires a cron expression string in the spec to compute next_run_at.

Source

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

    if user is None:
        raise HTTPException(status_code=401, detail="Authentication required")
    if body.context_mode not in {"fresh_thread_per_run", "reuse_thread"}:
        raise HTTPException(status_code=422, detail="Unsupported context_mode")
    if body.context_mode == "reuse_thread":
        if not body.thread_id:
            raise HTTPException(status_code=422, detail="reuse_thread requires thread_id")
        if not await thread_store.check_access(body.thread_id, str(user.id), require_existing=True):
            raise HTTPException(status_code=404, detail="Thread not found")
    if body.schedule_type not in {"once", "cron"}:
        raise HTTPException(status_code=422, detail="Unsupported schedule_type")

    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"),
        )

View on GitHub (pinned to 1dd6ba1acb)

Solutions

  1. Include a string cron expression: {"cron": "0 9 * * 1-5"}.
  2. Validate the expression format client-side before sending (5 fields).
  3. Note the backend normalizes the expression, but it must be a syntactically valid cron string or the later ValueError path returns 422 with details.

Example fix

// before
{ "schedule_type": "cron", "schedule_spec": { "hour": 9 } }
// after
{ "schedule_type": "cron", "schedule_spec": { "cron": "0 9 * * *" } }
Defensive patterns

Strategy: validation

Validate before calling

if body["schedule_type"] == "cron":
    cron = body["schedule_spec"].get("cron")
    assert isinstance(cron, str) and cron.strip(), "schedule_spec.cron must be a non-empty string"
    assert len(cron.split()) == 5, "expected a 5-field cron expression"

Type guard

const isCronSpec = (spec: Record<string, unknown>): spec is { cron: string } =>
  typeof spec.cron === "string" && spec.cron.trim().length > 0;

Prevention

When it happens

Trigger: {"schedule_type": "cron", "schedule_spec": {}} or schedule_spec.cron being a number/object/null.

Common situations: Building schedule_spec dynamically and skipping the cron key; sending a numeric schedule like {"cron": 5}.

Related errors


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