unslothai/unsloth · error · RuntimeError
A diffusion load is already in progress.
Error message
A diffusion load is already in progress.
What it means
Concurrency guard inside the load lock: a new diffusion load is refused while another load is in progress. The check is `self._loading is not None and self._loading.error is None` - i.e. a LIVE load blocks, but a previously FAILED one does not (starting over a failed load is explicitly allowed). A fresh cancel_event and incremented token are created per load so an unload() can preempt the running worker's download.
Source
Thrown at studio/backend/core/inference/diffusion.py:1813
family_override = family_override,
model_kind = model_kind,
)
# Refuse an EXPLICIT precision this host can never honor BEFORE the load starts, so the
# route answers 409 with the reason instead of evicting the resident model, downloading
# several GB and only then failing. The declines that need the real footprint (a VRAM
# misfit, a failed build) can only be found mid-load and surface through load-progress.
self.assert_precision_available(
fam,
model_kind = resolve_model_kind(gguf_filename, model_kind),
transformer_quant = transformer_quant,
text_encoder_quant = text_encoder_quant,
gpu_ordinal = gpu_ordinal,
)
with self._lock:
# Allow starting over a previously-failed load, but not over a live one.
if self._loading is not None and self._loading.error is None:
raise RuntimeError("A diffusion load is already in progress.")
self._load_token += 1
token = self._load_token
# A NEW event per load, never a clear() of the shared one: unload() sets the event the running worker holds but also
# drops _loading, so clearing here would un-cancel that worker. Download preemption is best-effort; the token is the
# real commit guard.
cancel_event = threading.Event()
self._cancel_event = cancel_event
# Seed with the family fallback; the worker resolves the real base and updates this.
self._loading = _LoadingState(repo_id = repo_id, base_repo = fam.base_repo)
threading.Thread(
target = self._run_load,
kwargs = dict(
repo_id = repo_id,
gguf_filename = gguf_filename,
base_repo = base_repo,
family_override = family_override,
hf_token = hf_token,View on GitHub (pinned to 203007d190)
Solutions
- Wait for the in-progress load to finish (poll the load-progress/status surface) before issuing another.
- If the running load is wrong or stuck, call unload() first - it cancels the worker via the cancel event - then start the new load.
- In automation, serialize loads behind a queue or lock on the caller side so only one load request is ever outstanding.
- Note a FAILED load does not block: if this error appears with no visible load, inspect _loading.error - a stale failed state should have been cleared.
Example fix
# before: fire-and-forget second load
manager.load(repo_id="unsloth/FLUX.1-dev") # still downloading
manager.load(repo_id="unsloth/SD3.5-large") # RuntimeError: already in progress
# after: wait for idle, or unload first
while manager.is_loading():
time.sleep(0.5)
manager.load(repo_id="unsloth/SD3.5-large") Defensive patterns
Strategy: retry
Validate before calling
def can_start_load(manager) -> bool:
"""True when no live load is running (a failed one does not block)."""
loading = manager._loading # or the public load-progress/status surface
return loading is None or loading.error is not None Try / catch
try:
manager.load(repo_id=repo)
except RuntimeError as e:
if "already in progress" in str(e):
wait_for_load_completion(manager) # poll status, then retry once
manager.load(repo_id=repo)
else:
raise Prevention
- Serialize model loads client-side: one outstanding load request at a time, disable the load button while in progress.
- Offer unload/cancel as the escape hatch - unload() drops _loading and cancels the worker via its cancel event.
- Poll load-progress until idle rather than guessing timings; downloads can be long.
- Remember a FAILED load never blocks a new one - if this fires with nothing visible, inspect the failed state instead of waiting.
When it happens
Trigger: Issuing a second load (or route-triggered model switch) while the first load's background thread is still downloading/building - e.g. the user clicks a second model while the first is still in load-progress, or an automation fires two loads concurrently.
Common situations: Impatient double-click in the Studio UI; an orchestrator retrying/switching models without waiting for the previous load to finish; a load that stalls on a slow download while the user picks a different model.
Related errors
- deadline reached while pacing before {method} {_redact_url(u
- The requested LoRA adapters could not be applied: baking ada
- Diffusion generation was cancelled.
- This quantized (int8/fp8) load was built without LoRA adapte
- No diffusion model is loaded.
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/84e5d64d9d397d63.
Report an issue: GitHub.