unslothai/unsloth · error · HTTPException

Training start request not found

Error message

Training start request not found

What it means

HTTP 404 from GET /training/start-requests/{start_request_id} when the backend's get_start_request returns no record for the given id. The id either never existed, was mistyped, or the record was cleaned up/expired server-side.

Source

Thrown at studio/backend/routes/training.py:1066

    # Off the event loop: the ROCm fallbacks shell out (Windows perf counters, sysfs) and the System view polls this route.
    return await asyncio.to_thread(get_visible_gpu_utilization)


@router.get("/start-requests/{start_request_id}", response_model = TrainingStartRequestStatus)
async def get_training_start_request(
    start_request_id: str = ApiPath(
        ...,
        min_length = 1,
        max_length = 128,
        pattern = TRAINING_REQUEST_ID_PATTERN,
    ),
    current_subject: str = Depends(get_current_subject),
):
    backend = get_training_backend()
    record = backend.get_start_request(start_request_id)
    if record is None:
        raise HTTPException(status_code = 404, detail = "Training start request not found")
    return _start_request_status_response(record)


def _start_request_status_response(record) -> TrainingStartRequestStatus:
    return TrainingStartRequestStatus(
        start_request_id = record.start_request_id,
        job_id = record.job_id,
        state = record.state,
        message = record.message,
        error = record.error,
        error_code = record.error_code,
    )


@router.post("/start-requests/{start_request_id}/acknowledge")
async def acknowledge_training_start_request(
    start_request_id: str = ApiPath(
        ...,

View on GitHub (pinned to 203007d190)

Solutions

  1. Re-fetch the list of start requests (listing endpoint or job status) to obtain the current valid start_request_id
  2. Verify the id matches TRAINING_REQUEST_ID_PATTERN and was not truncated or altered in transit
  3. If the backend restarted, submit a new training start request to get a fresh id

Example fix

// before
resp = client.get(f"/training/start-requests/{start_request_id}")  # 404

// after
if resp.status_code == 404:
    # id is gone (expired or backend restarted) - create a new start request
    resp = client.post("/training/start", payload)
    start_request_id = resp.json()["start_request_id"]
Defensive patterns

Strategy: validation

Validate before calling

import re
TRAINING_REQUEST_ID_PATTERN = r'^[A-Za-z0-9_-]{1,128}$'  # align with backend pattern

def valid_start_request_id(rid: str) -> bool:
    return bool(rid) and re.fullmatch(TRAINING_REQUEST_ID_PATTERN, rid) is not None

Type guard

def is_start_request_id(v: object) -> TypeGuard[str]:
    return isinstance(v, str) and valid_start_request_id(v)

Try / catch

resp = client.get(f"/training/start-requests/{rid}")
if resp.status_code == 404:
    # id unknown/expired: re-enumerate or submit a new start request
    rid = client.post("/training/start", payload).json()["start_request_id"]

Prevention

When it happens

Trigger: GET /training/start-requests/{id} with an id that does not match any recorded start request: wrong string, truncated id, or a request record already reaped after job completion.

Common situations: Client persisted an id across a backend restart that lost in-memory state; copy/paste truncation of the id; polling a request that finished and was garbage-collected.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/b06c4b2e72a76dec. Report an issue: GitHub.