{"record":{"id":"cf259845ffb58002","repo":"unslothai/unsloth","slug":"path-must-be-a-directory-not-a-file-cf2598","errorCode":null,"errorMessage":"Path must be a directory, not a file","messagePattern":"Path must be a directory, not a file","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"warning","filePath":"studio/backend/hub/storage/scan_folders.py","lineNumber":127,"sourceCode":"        _ensure_schema(conn)\n        rows = conn.execute(\n            \"SELECT id, path, created_at FROM scan_folders ORDER BY created_at\"\n        ).fetchall()\n        return [dict(row) for row in rows]\n    finally:\n        conn.close()\n\n\ndef add_scan_folder_with_status(path: str) -> tuple[dict, bool]:\n    \"\"\"Add a readable scan folder and return its row plus whether it was inserted.\"\"\"\n    if not path or not path.strip():\n        raise ValueError(\"Path cannot be empty\")\n    normalized = os.path.realpath(os.path.expanduser(normalize_path(path.strip())))\n\n    if not os.path.exists(normalized):\n        raise ValueError(\"Path does not exist\")\n    if not os.path.isdir(normalized):\n        raise ValueError(\"Path must be a directory, not a file\")\n    if not os.access(normalized, os.R_OK | os.X_OK):\n        raise ValueError(\"Path is not readable\")\n    if is_local_filesystem_root(normalized):\n        # A local fs root (\"/\", \"C:\\\\\") would expose denied system dirs via browse;\n        # a UNC share root (\\\\server\\share) has none under it and stays registerable.\n        raise ValueError(\"The filesystem root cannot be registered\")\n    if _contains_sensitive_path_component(normalized):\n        raise ValueError(\"Credential or configuration directories are not allowed\")\n\n    is_win = platform.system() == \"Windows\"\n    check = os.path.normcase(normalized) if is_win else normalized\n    for prefix in _denied_path_prefixes():\n        if check == prefix or check.startswith(prefix + os.sep):\n            if prefix == \"/run\" and is_linux_run_media_path(check):\n                continue\n            raise ValueError(f\"Path under {prefix} is not allowed\")\n\n    conn = get_connection()","sourceCodeStart":109,"sourceCodeEnd":145,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/hub/storage/scan_folders.py#L109-L145","documentation":"Validation error from add_scan_folder_with_status: the path exists but os.path.isdir() is False — a regular file was submitted. Scan folders must be directories because the inventory walks them for model weights.","triggerScenarios":"Registering a file like /data/models/model.gguf or /home/user/config.yaml as a scan folder.","commonSituations":"Users pasting the path to a downloaded weight file instead of its folder; drag-and-drop from a file manager yielding a file path; confusion between scan folders (directories) and model weight files (accepted elsewhere).","solutions":["Register the containing directory instead of the file.","If the intent was to point at one model, use the model-path/custom-folder mechanism that accepts weight files, not scan folders."],"exampleFix":"# before\nadd_scan_folder('/data/models/llama.gguf')\n# after\nadd_scan_folder('/data/models')","handlingStrategy":"validation","validationCode":"import os\n\ndef is_registerable_dir(path: str) -> bool:\n    p = os.path.realpath(os.path.expanduser(path.strip()))\n    return os.path.isdir(p)","typeGuard":null,"tryCatchPattern":null,"preventionTips":["In pickers, restrict selection to directories only.","If the user picked a weight file, offer its parent directory automatically."],"tags":["validation","scan-folders","user-input"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}