unslothai/unsloth · error · HTTPException
Models folder path is not a directory: {path}
Error message
Models folder path is not a directory: {path} What it means
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.
Source
Thrown at studio/backend/hub/services/models/local_inventory.py:1003
def get_models_folder_response() -> dict:
"""Return the directory where downloaded models are stored.
This is the active HF hub cache (honors ``HF_HOME`` / ``HF_HUB_CACHE``);
the desktop app reveals it in the OS file manager.
"""
path = _resolve_hf_cache_dir()
# Create it if missing so "Open folder" works before the first download:
# HF builds the cache lazily, and studio only pre-creates the *default*
# dir, not a user's explicit HF_HOME / HF_HUB_CACHE.
try:
path.mkdir(parents = True, exist_ok = True)
except OSError as e:
raise HTTPException(
status_code = 500,
detail = f"Failed to create models folder: {path}: {e}",
) from e
if not path.is_dir():
raise HTTPException(
status_code = 500,
detail = f"Models folder path is not a directory: {path}",
)
return {"path": str(path)}
def get_scan_folders_response() -> dict:
return {"folders": list_scan_folders()}
def add_scan_folder_response(path: str) -> dict:
try:
folder, inserted = add_scan_folder_with_status(_coerce_scan_folder_path(path))
except ValueError as e:
logger.warning("Scan folder rejected: %s (path=%s)", e, path)
raise HTTPException(status_code = 400, detail = str(e))
logger.info("Scan folder added: %s", folder.get("path"))
if inserted:View on GitHub (pinned to 203007d190)
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.
Example fix
# before: HF_HOME=$HOME/.cache/hf where ~/.cache/hf -> somefile rm ~/.cache/hf && mkdir -p ~/.cache/hf # after: HF_HOME=$HOME/.cache/hf (real directory)
Defensive patterns
Strategy: validation
Validate before calling
import os
def cache_path_is_real_dir() -> bool:
p = os.environ.get("HF_HOME") or os.path.expanduser("~/.cache/huggingface")
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))
# simpler:
def cache_ok() -> bool:
p = os.environ.get("HF_HOME") or os.path.expanduser("~/.cache/huggingface")
return os.path.isdir(p) and os.path.isdir(os.path.realpath(p)) Prevention
- 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).
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- Failed to read the local dataset cache.
- Failed to create models folder: {path}: {e}
- failed to delete uploaded files
- GGUF conversion produced a symlink, refusing to relocate it:
- Linked folder is no longer a regular directory
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/95bb3d2e0e82a97c.
Report an issue: GitHub.