unslothai/unsloth · error · ValueError

ControlNet is not supported for the '{fam.name}' model famil

Error message

ControlNet is not supported for the '{fam.name}' model family.

What it means

Raised by `_controlnet_pipe` when a ControlNet generation is requested but the model family declares neither `controlnet_pipeline_class` nor `controlnet_model_class`. ControlNet support is per-family: the loader needs both a diffusers pipeline class and a model class to assemble `Pipeline.from_pipe(base, controlnet=model)`. Missing attributes mean the family simply has no ControlNet integration, and the error is a clean ValueError.

Source

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

        pipe = getattr(diffusers, class_name).from_pipe(state.pipe, torch_dtype = None)
        # Publish to the shared aux cache only if THIS load is still current: from_pipe runs without _lock, so an unload can null _state and caching would hand out stale modules.
        with self._lock:
            if self._state is state:
                self._aux_pipes[class_name] = pipe
        return pipe

    def _controlnet_pipe(self, state: _LoadState, resolved_cn: Any, cancel: threading.Event) -> Any:
        """Build (once, cached) the family's diffusers ControlNet pipeline around the requested
        ControlNet model. The ControlNet model is a small extra module loaded via from_pretrained
        and cached by id; the pipeline is assembled with ``Pipeline.from_pipe(base,
        controlnet=model)`` -- reusing the resident base modules at their loaded dtype (no reload,
        no recast; torch_dtype=None for the same reason as _workflow_pipe). Raises a clear
        ValueError when the family declares no ControlNet classes."""
        fam = state.family
        pipe_cls_name = getattr(fam, "controlnet_pipeline_class", None)
        model_cls_name = getattr(fam, "controlnet_model_class", None)
        if not pipe_cls_name or not model_cls_name:
            raise ValueError(f"ControlNet is not supported for the '{fam.name}' model family.")
        import diffusers

        cn_model = self._cn_models.get(resolved_cn.id)
        if cn_model is None:
            if cancel.is_set():
                raise RuntimeError(DIFFUSION_CANCELLED_MSG)
            # resolve_controlnet accepts a bare owner/name without the trust gate and from_pretrained would execute a malicious
            # pickle, so run the same Hub malware preflight. It fails OPEN, so a remote repo also forces safetensors below.
            remote_cn = not getattr(resolved_cn, "is_local", False)
            if remote_cn:
                from utils.security import evaluate_file_security
                _cn_fs = evaluate_file_security(resolved_cn.path, hf_token = state.hf_token or None)
                if _cn_fs.blocked:
                    raise ValueError(_cn_fs.reason)
            # Keep at most one ControlNet resident, else swapping ControlNets accumulates until OOM.
            if self._cn_models or self._cn_pipes:
                self._cn_models.clear()
                self._cn_pipes.clear()

View on GitHub (pinned to 203007d190)

Solutions

  1. Remove the controlnet parameter from the generate call for this family.
  2. Reload a model family that declares ControlNet support (one with controlnet_pipeline_class set).
  3. If you own the family definitions, add the correct pipeline/model class names to enable ControlNet for that family.

Example fix

# before
diffusion.generate(prompt="...", controlnet=(cn_id, img_b64, "canny", 0.8, 0.0, 1.0))  # family lacks ControlNet
# after
diffusion.generate(prompt="...", controlnet=None)
Defensive patterns

Strategy: type-guard

Validate before calling

fam = diffusion.loaded_family()
if controlnet_spec is not None and not fam.controlnet_pipeline_class:
    controlnet_spec = None  # or reject client-side

Type guard

def supports_controlnet(family) -> bool:
    """Family declares both pipeline and model classes for ControlNet."""
    return bool(getattr(family, "controlnet_pipeline_class", None)) and bool(getattr(family, "controlnet_model_class", None))

Try / catch

try:
    diffusion.generate(prompt=p, controlnet=cn)
except ValueError as e:
    if "ControlNet is not supported" in str(e):
        diffusion.generate(prompt=p)  # drop controlnet
    else:
        raise

Prevention

When it happens

Trigger: Calling generate() with a `controlnet` tuple (id, control_image_b64, control_type, strength, guidance_start, guidance_end) while the loaded state's family lacks `controlnet_pipeline_class` or `controlnet_model_class` attributes.

Common situations: Using ControlNet with a DiT family that has no ControlNet pipeline support yet; UI allowing ControlNet controls for every model; loading Flux/SD-family variants whose registry entry omits ControlNet classes.

Related errors


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