unslothai/unsloth · error · RuntimeError

No diffusion model is loaded.

Error message

No diffusion model is loaded.

What it means

generate() precondition: `self._state` is None, meaning no diffusion model is currently loaded (never loaded, or unloaded). The local `state` reference is how the rest of generate() survives concurrent unloads, but if it is None at entry there is nothing to run, so RuntimeError(DIFFUSION_NOT_LOADED_MSG) raises immediately under the lock.

Source

Thrown at studio/backend/core/inference/diffusion.py:5291

        reference_images: Optional[list[str]] = None,
        # LoRA (id, weight) pairs; loaded non-fused and activated for this generation. None/empty clears.
        loras: Optional[list[tuple[str, float]]] = None,
        # ControlNet (id, control_image_b64, control_type, strength, guidance_start, guidance_end). None = off.
        controlnet: Optional[tuple[str, str, str, float, float, float]] = None,
    ) -> dict[str, Any]:
        import torch
        from PIL import Image

        # Per-generation cancel Event that unload()/a superseding load set (under _lock) to abort just this denoise.
        cancel = threading.Event()
        with self._generate_lock:
            with self._lock:
                # A teardown is waiting for this lock and Python locks are not FIFO, so refuse rather than start a denoise on a pipeline that is already being torn down.
                if self._teardown_waiters:
                    raise RuntimeError(DIFFUSION_CANCELLED_MSG)
                state = self._state
                if state is None:
                    raise RuntimeError(DIFFUSION_NOT_LOADED_MSG)
                # Register under _lock so unload()/a load can signal THIS generation.
                self._active_generate_cancel = cancel
                # Publish an active (step 0) state before the slow pre-denoise setup so a reload mount probe does not read idle.
                self._gen = _GenState(total_steps = steps)
            try:
                # FIRST, before any device object exists. This worker is not the thread that loaded
                # the pipeline, so until it is pinned the un-indexed state.device below -- and the
                # ControlNet placement further down -- resolve to its own default card while the
                # weights sit on the selected one.
                self._state_device_target(state)
                # The local `state` ref keeps the pipe alive even if unload() nulls _state. Resolve the per-image (prompt, seed) jobs
                # up front: N prompts, one prompt x N seeds, or one prompt deriving base..base+batch_size-1 (as the native engine does).
                jobs, seed = resolve_batch_jobs(
                    prompt = prompt,
                    prompts = prompts,
                    seed = seed,
                    seeds = seeds,
                    batch_size = batch_size,

View on GitHub (pinned to 203007d190)

Solutions

  1. Call load() and wait for success before generate().
  2. Check the loaded-model status endpoint before dispatching generation work.
  3. If a previous load failed, address its error (VRAM, repo access) first.

Example fix

# before
diffusion.generate(prompt="a cat")  # nothing loaded
# after
diffusion.load(model=repo)
diffusion.generate(prompt="a cat")
Defensive patterns

Strategy: validation

Validate before calling

if diffusion.loaded_model() is None:  # status endpoint / loaded-state probe
    await diffusion.load(model=repo)
result = diffusion.generate(prompt=p)

Type guard

def is_loaded(diffusion) -> bool:
    """A pipeline state is resident and generate() can proceed."""
    return diffusion.loaded_model() is not None

Try / catch

try:
    diffusion.generate(prompt=p)
except RuntimeError as e:
    if "No diffusion model is loaded" in str(e):
        await diffusion.load(model=repo)
        return diffusion.generate(prompt=p)
    raise

Prevention

When it happens

Trigger: Calling generate() before any successful load(), after unload(), or after a failed load left `_state` null. The check `state = self._state; if state is None: raise` fires under `_lock`.

Common situations: API clients firing a generation request before the load request completes; UI allowing generate while the model slot is empty; a previous load failed (OOM, bad repo) and the client did not check the result.

Related errors


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