unslothai/unsloth · error · ValueError
Unknown control type {control_type!r} for a union ControlNet
Error message
Unknown control type {control_type!r} for a union ControlNet. Use one of: {', '.join(sorted(_UNION_CONTROL_MODES))}, or passthrough. What it means
union_control_mode() was asked for a control type that is not one of the seven union head indices (blur, canny, depth, gray, lq, pose, tile) nor ''/'passthrough'. Union ControlNet models pick their head via an integer control_mode, so an unrecognized type would silently run the wrong head; this ValueError makes the route return 400 instead.
Source
Thrown at studio/backend/core/inference/diffusion_controlnet.py:222
def union_control_mode(spec_id: str, control_type: str) -> Optional[int]:
"""The integer ``control_mode`` for a union ControlNet, or None.
A union model requires a concrete mode. A known mode maps to its index; ``passthrough`` (or
empty) defaults to 0 (canny head). An unknown/typo'd type raises ValueError so the route
returns a 400 instead of running the wrong head. A non-union entry returns None."""
entry = _catalog_by_id().get(spec_id)
if entry is None:
# A union model may be named by its bare repo id, so match on repo_id too (the catalog is keyed by short id), else the union runs the wrong head.
entry = next((e for e in _CURATED if e.repo_id and e.repo_id == spec_id), None)
if entry is None or not entry.is_union:
return None
ct = (control_type or "").strip().lower()
if ct in _UNION_CONTROL_MODES:
return _UNION_CONTROL_MODES[ct]
if ct in ("", "passthrough"):
return 0 # preprocessed map, no intrinsic mode; canny is the default head
raise ValueError(
f"Unknown control type {control_type!r} for a union ControlNet. Use one of: "
f"{', '.join(sorted(_UNION_CONTROL_MODES))}, or passthrough."
)
def preprocess_control(image: Any, control_type: str) -> Any:
"""Turn a source image into a control map.
``passthrough`` returns the image unchanged. ``canny`` derives a dependency-free gradient edge
map (a rough stand-in for true Canny). Unknown types pass through so a new type never fails.
"""
ct = (control_type or "passthrough").strip().lower()
if ct != "canny":
return image
import numpy as np
from PIL import Image
gray = np.asarray(image.convert("L"), dtype = np.float32)View on GitHub (pinned to 203007d190)
Solutions
- Use one of the supported types: blur, canny, depth, gray, lq, pose, tile — or 'passthrough' (empty string also works and maps to the canny head)
- Check the entry's control_types / is_union via list_controlnets() before submitting
- Frontend: build the dropdown from sorted(_UNION_CONTROL_MODES) + 'passthrough' instead of a hardcoded generic list
Example fix
# before
mode = union_control_mode("xinsir-controlnet-union", "scribble")
# after
mode = union_control_mode("xinsir-controlnet-union", "canny")
# or, for an already-preprocessed control map:
mode = union_control_mode("xinsir-controlnet-union", "passthrough") Defensive patterns
Strategy: validation
Validate before calling
from studio.backend.core.inference.diffusion_controlnet import _UNION_CONTROL_MODES
def union_control_type_valid(control_type: str) -> bool:
ct = (control_type or "passthrough").strip().lower()
return ct in _UNION_CONTROL_MODES or ct in ("", "passthrough") Try / catch
try:
mode = union_control_mode(spec_id, control_type)
except ValueError as e:
return bad_request(str(e)) # lists the accepted types verbatim Prevention
- Drive the UI dropdown from sorted(_UNION_CONTROL_MODES) + 'passthrough' instead of a generic control-type list
- Normalize control_type with .strip().lower() before sending
- Remember only union entries (is_union=True) raise; single-purpose models ignore the type here
When it happens
Trigger: Calling union_control_mode(spec_id_of_union_model, control_type) with a typo ('canny-edge', 'depth-midas', 'Pose') or a type only valid for non-union models (e.g. 'scribble', 'hed'); only raises when the resolved entry has is_union=True.
Common situations: Frontend dropdown sends a preprocessing type the union model does not have; client reuses control_type values from a single-purpose ControlNet against a union model; trailing whitespace/case variants are handled, but invented names are not.
Related errors
- unknown ControlNet '{spec_id}': not a local model, catalog e
- ControlNet is not supported for the '{fam.name}' model famil
- Diffusion generation was cancelled.
- {_cn_fs.reason}
- ControlNet currently combines with plain text-to-image only,
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/16feeb87f2537967.
Report an issue: GitHub.