{"record":{"id":"7565db82452e9c04","repo":"bytedance/deer-flow","slug":"authentication-required-7565db","errorCode":null,"errorMessage":"Authentication required","messagePattern":"Authentication required","errorType":"http","errorClass":"HTTPException","httpStatus":401,"severity":"error","filePath":"backend/app/gateway/routers/scheduled_tasks.py","lineNumber":76,"sourceCode":"@router.get(\"/scheduled-tasks\")\n@require_permission(\"threads\", \"read\")\nasync def list_scheduled_tasks(request: Request):\n    repo = get_scheduled_task_repo(request)\n    user = await get_optional_user_from_request(request)\n    if user is None:\n        return []\n    return await repo.list_by_user(str(user.id))\n\n\n@router.post(\"/scheduled-tasks\")\n@require_permission(\"threads\", \"write\")\nasync def create_scheduled_task(request: Request, body: ScheduledTaskCreateRequest):\n    config = get_config()\n    repo = get_scheduled_task_repo(request)\n    thread_store = get_thread_store(request)\n    user = await get_optional_user_from_request(request)\n    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)","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/bytedance/deer-flow/blob/1dd6ba1acb03700589994b0366c5d1c7d05e2eff/backend/app/gateway/routers/scheduled_tasks.py#L58-L94","documentation":"Raised as HTTP 401 by POST /api/scheduled-tasks when get_optional_user_from_request returns None — the request arrived without valid authentication credentials. The route decorator checks the threads:write permission first, but an anonymous request fails this explicit user check.","triggerScenarios":"Creating a scheduled task with no Authorization header, an expired/invalid token, or a token from a disabled user; the permission decorator may pass in permissive setups, then the user check fails.","commonSituations":"Scripting the API without first obtaining a session/token; frontend token expired; auth cookie not sent on a cross-origin request.","solutions":["Authenticate first (log in via the auth flow the deployment uses) and attach the token/cookie to the request.","Verify the token is unexpired and issued for this Gateway instance.","Ensure cookies are sent cross-origin (credentials: 'include', CORS allows it)."],"exampleFix":"# before\nrequests.post(f\"{BASE}/api/scheduled-tasks\", json=body)  # 401\n# after\nrequests.post(f\"{BASE}/api/scheduled-tasks\", json=body,\n              headers={\"Authorization\": f\"Bearer {token}\"})","handlingStrategy":"validation","validationCode":"assert auth_token, \"no token available; authenticate before creating scheduled tasks\"\nprobe = requests.get(f\"{BASE}/api/scheduled-tasks\", headers={\"Authorization\": f\"Bearer {auth_token}\"})\nassert probe.status_code != 401, \"token invalid or expired\"","typeGuard":null,"tryCatchPattern":"resp = requests.post(f\"{BASE}/api/scheduled-tasks\", json=body, headers=auth)\nif resp.status_code == 401:\n    token = refresh_credentials()\n    resp = requests.post(f\"{BASE}/api/scheduled-tasks\", json=body,\n                         headers={\"Authorization\": f\"Bearer {token}\"})","preventionTips":["Always attach credentials to scheduled-task requests — there is no anonymous mode.","Refresh tokens proactively before expiry windows.","Include credentials in cross-origin fetches (credentials: 'include')."],"tags":["auth","scheduled-tasks","http-401"],"backgroundTag":null,"analyzedSha":"1dd6ba1acb03700589994b0366c5d1c7d05e2eff","analyzedAt":"2026-08-14T21:20:34.804Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}