{"record":{"id":"7163c2d63a9a8fb2","repo":"unslothai/unsloth","slug":"unknown-controlnet-spec-id-not-a-local-model","errorCode":null,"errorMessage":"unknown ControlNet '{spec_id}': not a local model, catalog entry, or HF repo id","messagePattern":"unknown ControlNet '(.+?)': not a local model, catalog entry, or HF repo id","errorType":"validation","errorClass":"FileNotFoundError","httpStatus":400,"severity":"error","filePath":"studio/backend/core/inference/diffusion_controlnet.py","lineNumber":188,"sourceCode":"        if entry.families and fam and fam not in {f.lower() for f in entry.families}:\n            raise ValueError(\n                f\"ControlNet '{spec_id}' is for {', '.join(entry.families)}, not the loaded \"\n                f\"'{family}' model; pick a ControlNet built for this family.\"\n            )\n        if entry.source == \"local\":\n            path = entry.local_path or \"\"\n            if not path or not Path(path).is_dir():\n                raise FileNotFoundError(f\"ControlNet '{spec_id}' is no longer present on disk\")\n            return ResolvedControlNet(spec_id, path, is_local = True)\n        if not entry.repo_id:\n            raise ValueError(f\"ControlNet '{spec_id}' has no repo\")\n        return ResolvedControlNet(spec_id, entry.repo_id, is_local = False)\n\n    # A bare HF repo id (owner/name). STRICT shape so a filesystem-looking id can never reach from_pretrained.\n    if re.fullmatch(r\"[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*\", spec_id):\n        return ResolvedControlNet(spec_id, spec_id, is_local = False)\n\n    raise FileNotFoundError(\n        f\"unknown ControlNet '{spec_id}': not a local model, catalog entry, or HF repo id\"\n    )\n\n\n# Union ControlNet mode indices: a union model selects its head via an integer ``control_mode``.\n_UNION_CONTROL_MODES: dict[str, int] = {\n    \"canny\": 0,\n    \"tile\": 1,\n    \"depth\": 2,\n    \"blur\": 3,\n    \"pose\": 4,\n    \"gray\": 5,\n    \"lq\": 6,\n}\n\n\ndef union_control_mode(spec_id: str, control_type: str) -> Optional[int]:\n    \"\"\"The integer ``control_mode`` for a union ControlNet, or None.","sourceCodeStart":170,"sourceCodeEnd":206,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/inference/diffusion_controlnet.py#L170-L206","documentation":"resolve_controlnet() failed all three resolution paths: spec_id is not in the merged catalog (curated + local scan), not a curated repo_id, and does not match the strict 'owner/name' Hugging Face repo shape. The strict regex deliberately rejects anything that looks like a filesystem path so it can never reach from_pretrained.","triggerScenarios":"Calling resolve_controlnet() with a typo'd id, a bare model name not present in the catalog, an absolute/relative path ('/data/cnet', './cnet', 'C:\\\\cnet'), or an id containing spaces or invalid characters. Paths and single-segment names fail the r'[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*' fullmatch.","commonSituations":"Client sends a local filesystem path expecting a direct load; stale UI offering an entry removed from the catalog; copy-paste of a repo URL (huggingface.co/owner/name) instead of the bare repo id; uppercase/underscore typos.","solutions":["List valid ids with list_controlnets(family=...) and use one of those ids","If you meant a Hugging Face model, pass the bare repo id exactly as 'owner/name' (no scheme, no host, no path separators beyond one '/')","If you meant a local folder, place it in the scanned models directory with config.json plus weights so it appears in the catalog","Routes should map this FileNotFoundError to a 400 so the client sees the message"],"exampleFix":"# before\nresolve_controlnet(\"https://huggingface.co/lllyasviel/sd-controlnet-canny\")\n\n# after\nresolve_controlnet(\"lllyasviel/sd-controlnet-canny\")","handlingStrategy":"validation","validationCode":"import re\nfrom studio.backend.core.inference.diffusion_controlnet import list_controlnets\n\nHF_REPO = re.compile(r\"[A-Za-z0-9][A-Za-z0-9_.-]*/[A-Za-z0-9][A-Za-z0-9_.-]*\")\n\ndef controlnet_id_valid(spec_id: str) -> bool:\n    if spec_id in {e.id for e in list_controlnets()}:\n        return True\n    return bool(HF_REPO.fullmatch(spec_id))","typeGuard":null,"tryCatchPattern":"try:\n    resolved = resolve_controlnet(spec_id, family=fam)\nexcept FileNotFoundError as e:\n    return bad_request(str(e))  # message lists all three accepted shapes","preventionTips":["Build ControlNet pickers from list_controlnets() plus validated 'owner/name' input only","Strip URLs down to owner/name before calling resolve; never pass filesystem paths","Map this FileNotFoundError to 400 in routes so clients see the guidance"],"tags":["controlnet","input-validation","huggingface","diffusion"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}