{"record":{"id":"0f64cbb13746d8b2","repo":"bytedance/deer-flow","slug":"cron-schedule-requires-schedule-spec-cron","errorCode":null,"errorMessage":"cron schedule requires schedule_spec.cron","messagePattern":"cron schedule requires schedule_spec\\.cron","errorType":"http","errorClass":"HTTPException","httpStatus":422,"severity":"warning","filePath":"backend/app/gateway/routers/scheduled_tasks.py","lineNumber":93,"sourceCode":"    if user is None:\n        raise HTTPException(status_code=401, detail=\"Authentication required\")\n    if body.context_mode not in {\"fresh_thread_per_run\", \"reuse_thread\"}:\n        raise HTTPException(status_code=422, detail=\"Unsupported context_mode\")\n    if body.context_mode == \"reuse_thread\":\n        if not body.thread_id:\n            raise HTTPException(status_code=422, detail=\"reuse_thread requires thread_id\")\n        if not await thread_store.check_access(body.thread_id, str(user.id), require_existing=True):\n            raise HTTPException(status_code=404, detail=\"Thread not found\")\n    if body.schedule_type not in {\"once\", \"cron\"}:\n        raise HTTPException(status_code=422, detail=\"Unsupported schedule_type\")\n\n    schedule_spec = dict(body.schedule_spec)\n    try:\n        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","sourceCodeStart":75,"sourceCodeEnd":111,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/scheduled_tasks.py#L75-L111","documentation":"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.","triggerScenarios":"{\"schedule_type\": \"cron\", \"schedule_spec\": {}} or schedule_spec.cron being a number/object/null.","commonSituations":"Building schedule_spec dynamically and skipping the cron key; sending a numeric schedule like {\"cron\": 5}.","solutions":["Include a string cron expression: {\"cron\": \"0 9 * * 1-5\"}.","Validate the expression format client-side before sending (5 fields).","Note the backend normalizes the expression, but it must be a syntactically valid cron string or the later ValueError path returns 422 with details."],"exampleFix":"// before\n{ \"schedule_type\": \"cron\", \"schedule_spec\": { \"hour\": 9 } }\n// after\n{ \"schedule_type\": \"cron\", \"schedule_spec\": { \"cron\": \"0 9 * * *\" } }","handlingStrategy":"validation","validationCode":"if body[\"schedule_type\"] == \"cron\":\n    cron = body[\"schedule_spec\"].get(\"cron\")\n    assert isinstance(cron, str) and cron.strip(), \"schedule_spec.cron must be a non-empty string\"\n    assert len(cron.split()) == 5, \"expected a 5-field cron expression\"","typeGuard":"const isCronSpec = (spec: Record<string, unknown>): spec is { cron: string } =>\n  typeof spec.cron === \"string\" && spec.cron.trim().length > 0;","tryCatchPattern":null,"preventionTips":["Build schedule_spec from a structured cron editor so the cron key is always present.","Validate cron shape client-side with a cron parser before submit."],"tags":["scheduled-tasks","cron","validation","http-422"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}