unslothai/unsloth · warning · ValueError

Path must be a folder or model weight file

Error message

Path must be a folder or model weight file

What it means

Raised when the resolved path exists and is a regular file, but its lowercase suffix is not one of the recognized model-weight extensions {.gguf, .safetensors, .bin}. The inventory layer derives the model root from a weight file by returning its parent directory, so it must first confirm the file actually looks like model weights by extension.

Source

Thrown at studio/backend/hub/services/models/local_inventory.py:623

        except (OSError, ValueError) as e:
            raise ValueError(f"Path is not readable: {e}") from e
        if slash_exists:
            normalized = slash_normalized
            try:
                is_dir = normalized.is_dir()
                is_file = normalized.is_file()
            except (OSError, ValueError) as e:
                raise ValueError(f"Path is not readable: {e}") from e
            exists = True

    if not exists:
        return str(normalized)
    if is_dir:
        return str(normalized)
    if is_file:
        suffix = normalized.suffix.lower()
        if suffix not in {".gguf", ".safetensors", ".bin"}:
            raise ValueError("Path must be a folder or model weight file")
        return str(normalized.parent)
    return str(normalized)


async def _scan_source(label: str, scanner, path: Path) -> List[LocalModelInfo]:
    try:
        return await asyncio.to_thread(scanner, path)
    except Exception as e:
        logger.warning("Skipping %s scan for %s: %s", label, path, e)
        return []


async def _collect_models_from_default_sources(
    models_root: Path,
    hf_cache_dir: Path,
    legacy_hf: Path,
    hf_default: Path,
    lm_dirs: tuple[Path, ...],

View on GitHub (pinned to 203007d190)

Solutions

  1. Select the model's folder instead of the file — folders are accepted regardless of contents (the scanner walks them for weights).
  2. If the weights genuinely are model weights, rename/use a file with a .safetensors, .gguf, or .bin extension.
  3. Convert the artifact: .ckpt/.pt → safetensors via convert_hf_to_gguf.py style tooling or safetensors conversion scripts.

Example fix

# before
models_dir = "/models/llama2/config.json"
# after
models_dir = "/models/llama2"   # the folder containing the weights
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import Path

WEIGHT_SUFFIXES = {".gguf", ".safetensors", ".bin"}

def is_acceptable_model_path(p: str) -> bool:
    path = Path(p)
    if path.is_dir():
        return True
    return path.is_file() and path.suffix.lower() in WEIGHT_SUFFIXES

Try / catch

try:
    root = resolve_model_root(path)
except ValueError as e:
    if "folder or model weight" in str(e):
        # user picked a file; suggest the containing directory
        suggest = str(Path(path).parent)

Prevention

When it happens

Trigger: Pointing models_dir or a custom scan folder at a file such as model.ckpt, model.pt, model.onnx, config.json, or README.md — anything that stats as a file without a .gguf/.safetensors/.bin suffix.

Common situations: Users selecting a checkpoint in PyTorch format (.ckpt/.pt) or an ONNX export, which this inventory does not index; accidentally selecting a config/readme inside a model folder instead of the folder itself; downloading a model whose weights ship under a non-standard extension.

Related errors


AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15). Data as JSON: /api/errors/af74bb24785010c1. Report an issue: GitHub.