unslothai/unsloth · warning · HTTPException

Training images cannot be changed while diffusion training i

Error message

Training images cannot be changed while diffusion training is active. Stop the run before uploading, importing, editing captions, or deleting images.

What it means

HTTP 409 from _require_diffusion_dataset_mutable(): the diffusion trainer re-opens dataset images during its loop, so any dataset mutation (upload, import, caption edit, delete) while a diffusion run is active would make the run nondeterministic or crash it with FileNotFoundError mid-step. The guard deliberately fails open — if the training service cannot be imported/state is unknowable, mutations are allowed — matching the start interlock.

Source

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

    except TrainingActiveError as exc:
        raise _DiffusionStartInFlight(
            "A diffusion (Images) LoRA training job is already running. "
            "Stop it before starting an LLM training run."
        ) from exc
    try:
        yield
    finally:
        cm.__exit__(None, None, None)


def _require_diffusion_dataset_mutable() -> None:
    """Reject a dataset mutation while a diffusion run is active.

    The trainer re-opens dataset images during the loop, so mutating underneath it makes the run
    nondeterministic or raises a FileNotFoundError mid-step. Fails open (a service-import failure
    never blocks a mutation on an unknowable state), matching the start interlock."""
    if _diffusion_training_active():
        raise HTTPException(
            status_code = 409,
            detail = (
                "Training images cannot be changed while diffusion training is active. "
                "Stop the run before uploading, importing, editing captions, or deleting images."
            ),
        )


def diffusion_dataset_interlock():
    """Dependency holding the dataset interlock for a whole mutating request.

    The check above only covers the instant it runs: every one of these endpoints then hands its
    filesystem work to a thread, and a ``/diffusion/start`` reserving in that gap would move
    captions or images underneath the preflight or the running trainer. As a yield dependency the
    registration spans the endpoint, so ``reserve()`` sees it and refuses instead. Fails open on an
    import error, like the check it replaces."""
    try:
        from core.training.diffusion_training_service import (

View on GitHub (pinned to 203007d190)

Solutions

  1. Stop the diffusion training run and wait for it to finish (poll /training/status).
  2. Retry the mutation once the run is idle.
  3. Queue dataset edits client-side and flush them when no run is active.
Defensive patterns

Strategy: validation

Validate before calling

const active = await get('/training/diffusion/status').catch(() => null)
if (active?.is_running) throw new Error('Stop the diffusion run before mutating training images')
await mutateDataset(...)

Try / catch

try { await uploadDatasetImage(file) } catch (e) { if (e.status === 409 && /cannot be changed while diffusion training/.test(e.detail)) { queueForLater(file); return } throw e }

Prevention

When it happens

Trigger: Calling any image dataset mutation endpoint (upload, import, caption edit, delete) while a diffusion (Images) training run is active, once the request enters the diffusion_dataset_interlock dependency.

Common situations: Users preparing the next dataset while a long SDXL/Flux LoRA run is going; automation scripts that upload images on a schedule regardless of training state.

Related errors


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