{"record":{"id":"1e2b75a8657802bf","repo":"unslothai/unsloth","slug":"the-diffusion-engine-changed-while-this-load-was-s","errorCode":null,"errorMessage":"The diffusion engine changed while this load was starting. Retry the load.","messagePattern":"The diffusion engine changed while this load was starting\\. Retry the load\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":409,"severity":"error","filePath":"studio/backend/core/inference/diffusion_engine_router.py","lineNumber":149,"sourceCode":"            logger.info(\"diffusion engine: sd_cpp\")\n        else:\n            logger.info(\"diffusion engine: diffusers (%s)\", reason or \"selected\")\n        return get_active_diffusion_engine()\n\n\ndef begin_load_on(expected_engine: Any, start: Callable[[], Any]) -> Any:\n    \"\"\"Run ``start`` under the transition lock, refusing if the engine changed since selection.\n\n    A load route selects its engine, then yields (device probe, arbiter acquire) before it\n    registers the load. A second /images/load picking the OTHER engine can transition in that\n    gap and unload the still-idle engine this request captured, which would then load a model\n    nothing can reach: generate / status / unload and the arbiter's evictor all resolve through\n    get_active_diffusion_engine(). Re-checking under the same lock the switch takes makes\n    selection and registration one operation.\n    \"\"\"\n    with _transition_lock:\n        if expected_engine is not get_active_diffusion_engine():\n            raise RuntimeError(\n                \"The diffusion engine changed while this load was starting. Retry the load.\"\n            )\n        return start()\n\n\ndef select_and_activate_engine(\n    fam: DiffusionFamily,\n    *,\n    hf_token: Optional[str] = None,\n    model_kind: Optional[str] = None,\n) -> Any:\n    \"\"\"Pick + activate the engine for loading ``fam`` on this host; return the engine.\n\n    Falls back to diffusers (recording a reason) when the native route is disabled, the device has\n    a usable GPU, MPS is not enabled, the family has no native asset, or the binary is unavailable\n    -- always BEFORE the slow load, so a fallback never strands a half-native load.\n    \"\"\"\n    # Non-GGUF loads run on diffusers only (the native engine consumes single-file GGUF only).","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/diffusion_engine_router.py#L131-L167","documentation":"begin_load_on() re-checks, under the same transition lock an engine switch takes, that the engine captured at selection time is still the active one. A concurrent request can transition engines in the gap between selection and load registration; loading then would produce a model nothing can reach (generate/status/unload all resolve through get_active_diffusion_engine()).","triggerScenarios":"Two /images/load requests picking different engines race: request A selects engine X, request B switches to engine Y (unloading idle X), then A calls begin_load_on(expected_engine=X, start=...) — the check sees Y active and raises. Also any code path that captures the engine, yields, then registers the load.","commonSituations":"Concurrent UI actions (a user flipping engine preference while a load starts); automation firing parallel load requests; GGUF-vs-diffusers selection flapping under concurrent traffic.","solutions":["Retry the whole load: re-select the engine and call begin_load_on again (the error message tells the user to retry)","Serialize loads client-side (one load request at a time) when the engine choice matters","For API wrappers, treat this RuntimeError as a transient conflict — back off briefly and re-run selection + load"],"exampleFix":"# before\nengine = get_active_diffusion_engine()\n# ... device probe, arbiter acquire (yield point) ...\nbegin_load_on(engine, start)  # RuntimeError if engine flipped\n\n# after\nfor attempt in range(3):\n    engine = get_active_diffusion_engine()\n    try:\n        return begin_load_on(engine, start)\n    except RuntimeError:\n        continue  # engine flipped; re-select and retry","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"for attempt in range(MAX_RETRIES):\n    expected = get_active_diffusion_engine()\n    try:\n        return begin_load_on(expected, start)\n    except RuntimeError as e:\n        if \"changed while this load was starting\" not in str(e):\n            raise\n        time.sleep(BACKOFF * 2**attempt)  # engine flipped; re-select and retry","preventionTips":["Keep the gap between engine selection and begin_load_on as short as possible","Serialize load requests client-side when engine preference can vary","Treat this RuntimeError as a transient conflict with a bounded retry, not a hard failure"],"tags":["concurrency","race-condition","retry","engine-switch","diffusion"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}