{"record":{"id":"95bb3d2e0e82a97c","repo":"unslothai/unsloth","slug":"models-folder-path-is-not-a-directory-path","errorCode":null,"errorMessage":"Models folder path is not a directory: {path}","messagePattern":"Models folder path is not a directory: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":500,"severity":"error","filePath":"studio/backend/hub/services/models/local_inventory.py","lineNumber":1003,"sourceCode":"def get_models_folder_response() -> dict:\n    \"\"\"Return the directory where downloaded models are stored.\n\n    This is the active HF hub cache (honors ``HF_HOME`` / ``HF_HUB_CACHE``);\n    the desktop app reveals it in the OS file manager.\n    \"\"\"\n    path = _resolve_hf_cache_dir()\n    # Create it if missing so \"Open folder\" works before the first download:\n    # HF builds the cache lazily, and studio only pre-creates the *default*\n    # dir, not a user's explicit HF_HOME / HF_HUB_CACHE.\n    try:\n        path.mkdir(parents = True, exist_ok = True)\n    except OSError as e:\n        raise HTTPException(\n            status_code = 500,\n            detail = f\"Failed to create models folder: {path}: {e}\",\n        ) from e\n    if not path.is_dir():\n        raise HTTPException(\n            status_code = 500,\n            detail = f\"Models folder path is not a directory: {path}\",\n        )\n    return {\"path\": str(path)}\n\n\ndef get_scan_folders_response() -> dict:\n    return {\"folders\": list_scan_folders()}\n\n\ndef add_scan_folder_response(path: str) -> dict:\n    try:\n        folder, inserted = add_scan_folder_with_status(_coerce_scan_folder_path(path))\n    except ValueError as e:\n        logger.warning(\"Scan folder rejected: %s (path=%s)\", e, path)\n        raise HTTPException(status_code = 400, detail = str(e))\n    logger.info(\"Scan folder added: %s\", folder.get(\"path\"))\n    if inserted:","sourceCodeStart":985,"sourceCodeEnd":1021,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/hub/services/models/local_inventory.py#L985-L1021","documentation":"HTTP 500 raised when mkdir(parents=True, exist_ok=True) returned without error but path.is_dir() is still False immediately after. This catches the races and edge cases mkdir can mask: path is (or became) a symlink to a regular file, or another process replaced the directory between creation and the check. It guarantees 'Open folder' never receives a non-directory.","triggerScenarios":"HF_HOME pointing at a symlink that resolves to a regular file; a concurrent process swapping the directory for a file (or a symlink to one) in the microseconds between mkdir and is_dir; exist_ok=True silently accepting an existing file at that name is NOT possible (mkdir would raise), so the realistic case is symlink-to-file.","commonSituations":"Users symlinking HF_HOME to a 'cache' that is actually a file; symlink chains created by dotfile managers; a broken symlink target that happens to be a file.","solutions":["Inspect the path: `ls -la <HF_HOME>` and confirm it is a directory or a symlink to a directory.","Replace the offending symlink/file with a real directory (rm the link, mkdir -p).","Repoint HF_HOME/HF_HUB_CACHE at a real directory."],"exampleFix":"# before: HF_HOME=$HOME/.cache/hf  where ~/.cache/hf -> somefile\nrm ~/.cache/hf && mkdir -p ~/.cache/hf\n# after: HF_HOME=$HOME/.cache/hf  (real directory)","handlingStrategy":"validation","validationCode":"import os\n\ndef cache_path_is_real_dir() -> bool:\n    p = os.environ.get(\"HF_HOME\") or os.path.expanduser(\"~/.cache/huggingface\")\n    return os.path.isdir(p) and not os.path.islink(os.path.realpath(p) and p or p) or os.path.isdir(os.path.realpath(p))\n# simpler:\ndef cache_ok() -> bool:\n    p = os.environ.get(\"HF_HOME\") or os.path.expanduser(\"~/.cache/huggingface\")\n    return os.path.isdir(p) and os.path.isdir(os.path.realpath(p))","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Avoid symlinking HF_HOME itself; symlink its inner directories (hub/, xet/) if layout flexibility is needed.","Validate isdir(realpath(p)) in config checks, not just isdir(p)."],"tags":["filesystem","http-500","symlink","race-condition","hf-cache"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}