unslothai/unsloth · error · FileNotFoundError
ControlNet '{spec_id}' is no longer present on disk
Error message
ControlNet '{spec_id}' is no longer present on disk What it means
resolve_controlnet() found a catalog entry with source='local' (discovered by scanning a models directory), but the entry's local_path is empty or no longer a directory on disk. The scan that built the entry and the resolve can happen at different times, so the folder may have been deleted, renamed, or moved in between.
Source
Thrown at studio/backend/core/inference/diffusion_controlnet.py:178
``family`` enforces compatibility: a ControlNet is architecture-specific, so an entry tagged
for another family is rejected here rather than loaded through the wrong pipeline later.
"""
entry = _catalog_by_id().get(spec_id)
if entry is None:
# A curated entry named by its full repo id must still hit the family gate below, not slip through the bare-repo fallback.
entry = next((e for e in _CURATED if e.repo_id and e.repo_id == spec_id), None)
if entry is not None:
# A direct API call could send an entry for another family; reject it before any download.
fam = (family or "").strip().lower()
if entry.families and fam and fam not in {f.lower() for f in entry.families}:
raise ValueError(
f"ControlNet '{spec_id}' is for {', '.join(entry.families)}, not the loaded "
f"'{family}' model; pick a ControlNet built for this family."
)
if entry.source == "local":
path = entry.local_path or ""
if not path or not Path(path).is_dir():
raise FileNotFoundError(f"ControlNet '{spec_id}' is no longer present on disk")
return ResolvedControlNet(spec_id, path, is_local = True)
if not entry.repo_id:
raise ValueError(f"ControlNet '{spec_id}' has no repo")
return ResolvedControlNet(spec_id, entry.repo_id, is_local = False)
# A bare HF repo id (owner/name). STRICT shape so a filesystem-looking id can never reach from_pretrained.
if re.fullmatch(r"[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*", spec_id):
return ResolvedControlNet(spec_id, spec_id, is_local = False)
raise FileNotFoundError(
f"unknown ControlNet '{spec_id}': not a local model, catalog entry, or HF repo id"
)
# Union ControlNet mode indices: a union model selects its head via an integer ``control_mode``.
_UNION_CONTROL_MODES: dict[str, int] = {
"canny": 0,
"tile": 1,View on GitHub (pinned to 203007d190)
Solutions
- Restore or re-create the ControlNet folder at the recorded local_path (must contain config.json plus loadable weights)
- Re-list the catalog (list_controlnets) to refresh the directory scan and pick a currently-present entry
- If the model is gone for good, switch to a curated/remote entry or a bare 'owner/name' Hugging Face repo id
- API authors: catch FileNotFoundError from resolve_controlnet and map it to a 400 with this message for the client
Example fix
// before
resolved = resolve_controlnet("my-local-cnet")
// after
from pathlib import Path
entry = _catalog_by_id().get("my-local-cnet")
if entry is None or entry.source == "local" and not Path(entry.local_path or "").is_dir():
entries = list_controlnets() # refresh scan, pick a live entry
resolved = resolve_controlnet(entries[0].id) Defensive patterns
Strategy: try-catch
Validate before calling
from pathlib import Path
from studio.backend.core.inference.diffusion_controlnet import list_controlnets
def controlnet_loadable(spec_id: str) -> bool:
return any(
e.id == spec_id and (e.source != "local" or Path(e.local_path or "").is_dir())
for e in list_controlnets()
) Try / catch
try:
resolved = resolve_controlnet(spec_id, family=fam)
except FileNotFoundError as e:
# catalog entry stale or id unknown -> 400 for the client, never a 500
raise HTTPBadRequest(str(e)) from e Prevention
- Refresh the catalog with list_controlnets() before showing choices in the UI so deleted folders drop out
- Keep local ControlNet folders (config.json + weights) inside the scanned models directory and avoid renaming them while the backend runs
- Treat FileNotFoundError from resolve_controlnet as a client error (400), not a server fault
When it happens
Trigger: Calling resolve_controlnet(spec_id) where spec_id is a folder name previously found under the local ControlNet models directory, after that folder was deleted, renamed, or made unreadable; or a hand-crafted ControlNetCatalogEntry(source='local', local_path='') / with a path on a disconnected drive.
Common situations: User deletes a ControlNet folder via the OS while the studio backend is running and the UI still shows the stale catalog entry; models stored on an external/network drive that unmounted; folder renamed to reorganize models.
Related errors
- Local base_repo is not a diffusers pipeline directory (no {i
- 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/a5c415a1c57a689e.
Report an issue: GitHub.