{"record":{"id":"7f7d85bc6897b2ec","repo":"bytedance/deer-flow","slug":"once-schedule-must-be-at-least-config-scheduler-m","errorCode":null,"errorMessage":"once schedule must be at least {config.scheduler.min_once_delay_seconds} seconds in the future","messagePattern":"once schedule must be at least (.+?) seconds in the future","errorType":"http","errorClass":"HTTPException","httpStatus":422,"severity":"warning","filePath":"backend/app/gateway/routers/scheduled_tasks.py","lineNumber":107,"sourceCode":"        validate_timezone(body.timezone)\n        if body.schedule_type == \"cron\":\n            raw_cron = schedule_spec.get(\"cron\")\n            if not isinstance(raw_cron, str):\n                raise HTTPException(status_code=422, detail=\"cron schedule requires schedule_spec.cron\")\n            schedule_spec[\"cron\"] = normalize_cron_expression(raw_cron)\n        next_run_at = compute_next_run_at(\n            body.schedule_type,\n            schedule_spec,\n            body.timezone,\n            now=datetime.now(UTC),\n        )\n    except ValueError as exc:\n        raise HTTPException(status_code=422, detail=str(exc)) from exc\n\n    if body.schedule_type == \"once\" and next_run_at is None:\n        raise HTTPException(status_code=422, detail=\"once schedule must be in the future\")\n    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:\n        raise HTTPException(\n            status_code=422,\n            detail=(f\"once schedule must be at least {config.scheduler.min_once_delay_seconds} seconds in the future\"),\n        )\n\n    return await repo.create(\n        task_id=f\"task-{uuid.uuid4().hex}\",\n        user_id=str(user.id),\n        thread_id=body.thread_id,\n        context_mode=body.context_mode,\n        assistant_id=\"lead_agent\",\n        title=body.title,\n        prompt=body.prompt,\n        schedule_type=body.schedule_type,\n        schedule_spec=schedule_spec,\n        timezone=body.timezone,\n        next_run_at=next_run_at,\n    )\n","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/scheduled_tasks.py#L89-L125","documentation":"Raised as HTTP 422 by POST /api/scheduled-tasks when a once schedule's next_run_at is fewer than config.scheduler.min_once_delay_seconds in the future. The scheduler requires a minimum lead time to register and dispatch one-shot tasks reliably.","triggerScenarios":"A once run_at only seconds ahead while min_once_delay_seconds (config.yaml -> scheduler) is larger (commonly tens of seconds or more).","commonSituations":"Users scheduling 'in 5 seconds'; operator raised the minimum delay; tests using near-immediate timestamps.","solutions":["Schedule the run at least min_once_delay_seconds ahead — the error message names the exact required number; use that + a safety margin.","If immediate execution is the goal, run the prompt directly via the chat/run API instead of a once task.","Operators can lower scheduler.min_once_delay_seconds in config.yaml if the default is too conservative, then restart the Gateway."],"exampleFix":"// before\nconst runAt = new Date(Date.now() + 5_000).toISOString(); // may be < min delay\n// after: use the minimum the backend enforces + margin\nconst runAt = new Date(Date.now() + (MIN_ONCE_DELAY_SECONDS + 30) * 1000).toISOString();","handlingStrategy":"validation","validationCode":"MIN_DELAY = get_scheduler_min_once_delay()  # from config/GW docs; match config.scheduler.min_once_delay_seconds\nfrom datetime import datetime, UTC, timedelta\nrun_at = datetime.fromisoformat(body[\"schedule_spec\"][\"run_at\"].replace(\"Z\", \"+00:00\"))\nassert run_at - datetime.now(UTC) >= timedelta(seconds=MIN_DELAY + 5), f\"need >= {MIN_DELAY}s lead time\"","typeGuard":"const isBeyondMinDelay = (iso: string, minDelaySec: number): boolean =>\n  (Date.parse(iso) - Date.now()) / 1000 > minDelaySec;","tryCatchPattern":"resp = requests.post(url, json=body, headers=auth)\nif resp.status_code == 422 and \"at least\" in resp.json().get(\"detail\", \"\"):\n    body[\"schedule_spec\"][\"run_at\"] = iso_now_plus(MIN_DELAY + 30)  # parse required delay from detail\n    resp = requests.post(url, json=body, headers=auth)","preventionTips":["Read the required minimum from the 422 detail and honor it + margin in the client.","Default the once-picker to minutes-ahead, not seconds-ahead.","For immediate runs, call the chat/run API directly instead of scheduling."],"tags":["scheduled-tasks","scheduler","validation","http-422","time"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}