{"record":{"id":"789963a99a0b4a61","repo":"unslothai/unsloth","slug":"training-start-request-no-longer-owns-the-current","errorCode":null,"errorMessage":"Training start request no longer owns the current job","messagePattern":"Training start request no longer owns the current job","errorType":"http","errorClass":"HTTPException","httpStatus":409,"severity":"warning","filePath":"studio/backend/routes/training.py","lineNumber":1122,"sourceCode":"async def cancel_training_start_request(\n    start_request_id: str = ApiPath(\n        ...,\n        min_length = 1,\n        max_length = 128,\n        pattern = TRAINING_REQUEST_ID_PATTERN,\n    ),\n    current_subject: str = Depends(get_current_subject),\n):\n    backend = get_training_backend()\n    try:\n        outcome, record = await asyncio.to_thread(\n            backend.cancel_start_request,\n            start_request_id,\n        )\n    except TrainingStartCancellationCapacityError as exc:\n        raise HTTPException(status_code = 429, detail = str(exc)) from exc\n    if outcome == \"superseded\":\n        raise HTTPException(\n            status_code = 409,\n            detail = \"Training start request no longer owns the current job\",\n        )\n    return _start_request_status_response(record)\n\n\ndef _background_video_generation_active() -> bool:\n    \"\"\"Whether a video clip is generating on the video backend's worker thread.\n\n    POST /video/generate returns at once and generates in the background, so an\n    in-flight clip is invisible to the keep-warm in-flight request count the\n    API-key training guards consult; ask the backend directly. Best-effort: a\n    probe failure must never block a training start.\"\"\"\n    try:\n        from core.inference.video import get_video_backend\n        return bool(get_video_backend().generate_progress().get(\"active\"))\n    except Exception as e:  # noqa: BLE001\n        logger.warning(\"Could not check video generation state for training guard: %s\", e)","sourceCodeStart":1104,"sourceCodeEnd":1140,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/routes/training.py#L1104-L1140","documentation":"HTTP 409 when cancel_start_request returns outcome 'superseded': the start request being cancelled no longer owns the current job (a newer start request has taken over the job slot), so cancelling it would not stop anything.","triggerScenarios":"POST cancel on an old start_request_id after a newer training start request has already replaced it as the owner of the current job.","commonSituations":"Client holds a stale id after re-submitting training start; concurrent automation where one flow starts a new job while another tries to cancel the old request.","solutions":["Fetch the current job id from the backend (job/status endpoints) and cancel via the current owning start request","If the goal was 'stop whatever is training', cancel the newest start request or the current job directly","Refresh cached start_request_id after every new /training/start call"],"exampleFix":"// before\nclient.post(f\"/training/start-requests/{old_id}/cancel\")  # 409 superseded\n\n// after\njob = client.get(\"/training/current-job\").json()\nowner_id = job[\"start_request_id\"]\nclient.post(f\"/training/start-requests/{owner_id}/cancel\")","handlingStrategy":"validation","validationCode":"def cancel_is_meaningful(status: dict) -> bool:\n    # only cancel the request that currently owns the job\n    return status.get(\"state\") not in (\"superseded\", \"completed\", \"failed\", \"cancelled\")","typeGuard":null,"tryCatchPattern":"resp = client.post(f\"/training/start-requests/{rid}/cancel\")\nif resp.status_code == 409 and \"no longer owns\" in resp.text:\n    current = client.get(\"/training/current-job\").json()\n    rid = current[\"start_request_id\"]  # cancel the actual owner","preventionTips":["Refresh the owning start_request_id before every cancel","Discard cached ids whenever a new /training/start succeeds","Treat 'superseded' as benign: the old request needs no cancellation"],"tags":["training","http-409","superseded","cancellation","stale-id"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}