{"record":{"id":"64837502de10e5ec","repo":"bytedance/deer-flow","slug":"scheduled-task-is-currently-running-retry-after-t","errorCode":null,"errorMessage":"Scheduled task is currently running; retry after the active execution finishes","messagePattern":"Scheduled task is currently running; retry after the active execution finishes","errorType":"http","errorClass":"HTTPException","httpStatus":409,"severity":"warning","filePath":"backend/app/gateway/routers/scheduled_tasks.py","lineNumber":33,"sourceCode":"    get_scheduled_task_run_repo,\n    get_scheduled_task_service,\n    get_thread_store,\n)\nfrom deerflow.scheduler.schedules import (\n    next_run_at as compute_next_run_at,\n)\nfrom deerflow.scheduler.schedules import (\n    normalize_cron_expression,\n    validate_timezone,\n)\nfrom deerflow.utils.thread_id import ThreadId\n\nrouter = APIRouter(prefix=\"/api\", tags=[\"scheduled-tasks\"])\n\n\ndef _ensure_task_mutable(task: dict[str, Any]) -> None:\n    if task.get(\"status\") == \"running\":\n        raise HTTPException(\n            status_code=409,\n            detail=\"Scheduled task is currently running; retry after the active execution finishes\",\n        )\n\n\nclass ScheduledTaskCreateRequest(BaseModel):\n    thread_id: ThreadId | None = None\n    context_mode: str = \"fresh_thread_per_run\"\n    title: str = Field(min_length=1)\n    prompt: str = Field(min_length=1)\n    schedule_type: str\n    schedule_spec: dict[str, Any]\n    timezone: str\n\n\nclass ScheduledTaskUpdateRequest(BaseModel):\n    context_mode: str | None = None\n    thread_id: ThreadId | None = None","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/scheduled_tasks.py#L15-L51","documentation":"Raised as HTTP 409 by _ensure_task_mutable when attempting to mutate (PATCH/DELETE, or any operation guarded by this helper) a scheduled task whose status is 'running'. The system prevents editing tasks mid-execution to keep the active run's inputs stable; retry after the execution completes.","triggerScenarios":"PATCH or DELETE /api/scheduled-tasks/{task_id} while the scheduler is actively executing that task; also any code path calling _ensure_task_mutable on a task dict with status == 'running'.","commonSituations":"User edits a cron task exactly as it fires; long-running scheduled execution overlapping a UI save; automation retrying an update immediately after start.","solutions":["Wait for the active execution to finish, verify status != 'running' via GET /api/scheduled-tasks/{task_id}, then retry the mutation.","For automation, implement retry-with-backoff on 409 with a cap rather than immediate retry.","If the task appears stuck in 'running' (crashed scheduler), restart the scheduler service so it finalizes the run state, then retry."],"exampleFix":"# before\nresp = requests.patch(f\"{BASE}/api/scheduled-tasks/{task_id}\", json=patch)\n# after: retry on 409\nfor attempt in range(5):\n    resp = requests.patch(f\"{BASE}/api/scheduled-tasks/{task_id}\", json=patch)\n    if resp.status_code != 409:\n        break\n    time.sleep(10 * (attempt + 1))","handlingStrategy":"retry","validationCode":"task = requests.get(f\"{BASE}/api/scheduled-tasks/{task_id}\", headers=auth).json()\nif task.get(\"status\") == \"running\":\n    defer_mutation(task_id)  # do not send PATCH/DELETE yet","typeGuard":"def is_task_mutable(task: dict) -> bool:\n    return task.get(\"status\") != \"running\"","tryCatchPattern":"for attempt in range(MAX_RETRIES):\n    resp = requests.patch(url, json=patch, headers=auth)\n    if resp.status_code != 409:\n        break\n    time.sleep(backoff(attempt))  # 409 = running; wait for execution to finish\nresp.raise_for_status()","preventionTips":["Check task status via GET before showing edit/delete affordances in the UI.","Back off exponentially on 409 — execution length is unknown.","Keep mutations idempotent so a delayed retry after execution is safe."],"tags":["scheduled-tasks","http-409","concurrency","retry"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}