{"record":{"id":"e22018af0ab94e17","repo":"unslothai/unsloth","slug":"family-name-needs-diffusers-pipeline-class","errorCode":null,"errorMessage":"'{family_name}' needs diffusers ({pipeline_class}), which this environment cannot import: {exc}. Install or repair it with: pip install -U diffusers.","messagePattern":"'(.+?)' needs diffusers \\((.+?)\\), which this environment cannot import: (.+?)\\. Install or repair it with: pip install -U diffusers\\.","errorType":"exception","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"studio/backend/core/inference/diffusion_families.py","lineNumber":1148,"sourceCode":"    try:\n        import diffusers\n        present = hasattr(diffusers, pipeline_class)\n        dummy_backends = _dummy_required_backends(getattr(diffusers, pipeline_class, None))\n    except Exception as exc:  # noqa: BLE001 -- see below: this check must never raise anything but its own ValueError\n        # Not this check's business under the default: it answers \"is the installed diffusers new enough for this\n        # family\", and with nothing importable there is no version to judge. Refusing would also break the native\n        # sd.cpp engine, which serves GGUF picks on a CPU or Apple host without diffusers. A pick that really needs\n        # it fails later, in the loader. The one thing that must not happen is a raise of the wrong type:\n        # ModuleNotFoundError is not the ValueError the routes map to 400, so it escapes /images/download-plan as a\n        # bare 500 with the message lost.\n        #\n        # The attribute probe is inside the try for the same reason. diffusers' top level is a lazy module, so\n        # ``hasattr`` is what actually imports the pipeline's submodule, and when that submodule's own dependencies\n        # are unsatisfiable it raises RuntimeError (\"Failed to import diffusers.pipelines...\") -- which hasattr does\n        # NOT swallow, since it only absorbs AttributeError. A partially usable diffusers install therefore escaped\n        # this guard exactly the way a missing one used to.\n        if strict:\n            raise ValueError(\n                f\"'{family_name}' needs diffusers ({pipeline_class}), which this environment \"\n                f\"cannot import: {exc}. Install or repair it with: pip install -U diffusers.\"\n            ) from None\n        return\n\n    if present and dummy_backends:\n        # A placeholder, not the pipeline. Under the default this is left alone like every other\n        # unusable install; strict refuses, because the trainer child imports the same placeholder\n        # and its from_pretrained raises only after the GPU residents are gone.\n        if not strict:\n            return\n        raise ValueError(\n            f\"'{family_name}' needs diffusers ({pipeline_class}), but this diffusers exports it as \"\n            f\"a placeholder, which it does when a backend it requires is unavailable. That class \"\n            f\"requires: {', '.join(dummy_backends)}. Check which of those this environment is \"\n            f\"missing and install it.\"\n        )\n","sourceCodeStart":1130,"sourceCodeEnd":1166,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/diffusion_families.py#L1130-L1166","documentation":"In strict mode (the training path), probing diffusers for the family's pipeline class raised while importing — diffusers is missing entirely, or it is a broken/lazy install whose pipeline submodule import fails (e.g. 'Failed to import diffusers.pipelines...' from unsatisfiable sub-dependencies). Strict refuses here because the trainer's spawn child would fail the same import only after GPU models were already freed. The guard always raises ValueError so routes map it to 400 with the message intact.","triggerScenarios":"Starting training for a diffusers-based family on a host where 'import diffusers' or the hasattr(diffusers, pipeline_class) probe raises: not installed, partially installed, or its dependencies (torch/transformers versions) unsatisfiable. Inference (strict=False) stays silent and only the too-old check applies.","commonSituations":"CPU or Apple host serving GGUF via sd.cpp with no diffusers installed, then a training request arrives; broken venv after upgrading torch without reinstalling diffusers; Python 3.9 environment holding an old or partial diffusers.","solutions":["pip install -U diffusers (as the message says) into the environment the trainer runs in","If it still fails, reinstall cleanly: pip uninstall -y diffusers && pip install -U diffusers, and check the chained exception for the missing sub-dependency","Verify with: python -c \"import diffusers; hasattr(diffusers, '<pipeline_class>')\" from the same interpreter/venv","Do not attempt training on hosts intentionally running diffusers-free sd.cpp; use a host with diffusers installed"],"exampleFix":"# before\n# host has no diffusers; training request for Flux2Klein -> ValueError\n\n# after\npip install -U diffusers\npython -c \"import diffusers; assert hasattr(diffusers, 'Flux2KleenPipeline')\"  # adjust class name","handlingStrategy":"validation","validationCode":"def diffusers_importable_for(pipeline_class: str) -> bool:\n    try:\n        import diffusers\n        return hasattr(diffusers, pipeline_class)  # probe imports the lazy submodule\n    except Exception:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    validate_family_pipeline(pipeline_class, family_name, strict=True)\nexcept ValueError as e:\n    # environment defect: surface the pip guidance to the user, do not start training\n    return bad_request(str(e))","preventionTips":["Pre-flight the trainer environment: python -c 'import diffusers' in the same venv the child uses","Install/repair diffusers on hosts that will train; keep sd.cpp-only hosts inference-only","Remember inference (strict=False) tolerates a missing diffusers — only training refuses"],"tags":["diffusers","environment","dependency","training","install"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}