unslothai/unsloth · error · HTTPException
Path is not in the browseable allowlist. Register it via POS
Error message
Path is not in the browseable allowlist. Register it via POST /api/models/scan-folders first, or pick a directory under your home folder.
What it means
Raised as a 403 by _resolve_browse_target when a resolved path component lands outside every allowlist root — checked with _is_path_inside_allowlist(resolved_child, resolved_roots) after resolve(). Its main purpose is defeating symlink escapes: a component that exists inside a root but resolves (via symlink) to a location outside all roots is rejected before it is used.
Source
Thrown at studio/backend/routes/models.py:1700
status_code = 404,
detail = f"Path does not exist: {os.path.basename(requested_path)}",
)
try:
resolved_child = child.resolve()
except OSError as exc:
logger.warning(
"browse-folders: invalid path component %r under %s: %s",
part,
current,
exc,
exc_info = True,
)
raise HTTPException(
status_code = 400,
detail = "Invalid path",
) from exc
if not _is_path_inside_allowlist(resolved_child, resolved_roots):
raise HTTPException(
status_code = 403,
detail = (
"Path is not in the browseable allowlist. Register it via "
"POST /api/models/scan-folders first, or pick a directory "
"under your home folder."
),
)
if contains_sensitive_path_component(str(resolved_child)):
raise HTTPException(
status_code = 403,
detail = "Credential or configuration directories are not browseable.",
)
if is_denied_system_path(str(resolved_child)):
raise HTTPException(
status_code = 403,
detail = "System directories are not browseable.",
)
current = resolved_childView on GitHub (pinned to 203007d190)
Solutions
- Register the symlink's real target as a scan folder via POST /api/models/scan-folders, then browse the real path directly.
- Remove intermediate symlinks that escape the allowlist, or move/copy the data inside an allowed root.
- Keep models under home/studio/outputs roots without escaping symlinks.
Example fix
# before
ln -s /mnt/bigdrive/models ~/models/link
GET /api/models/browse-folders?path=~models/link # 403
# after
POST /api/models/scan-folders {"path": "/mnt/bigdrive/models"}
GET /api/models/browse-folders?path=/mnt/bigdrive/models Defensive patterns
Strategy: validation
Validate before calling
import os
def escapes_allowlist(path: str, roots: list[str]) -> bool:
real = os.path.realpath(path)
real_roots = [os.path.realpath(r) for r in roots]
return not any(real == r or real.startswith(r + os.sep) for r in real_roots)
if escapes_allowlist(browse_path, scan_folder_roots):
raise ValueError('symlink target outside allowlist — register the real target instead') Try / catch
try:
entries = browse(path)
except HTTPError as e:
if e.response.status_code == 403 and 'allowlist' in e.response.json()['detail']:
register_scan_folder(os.path.realpath(path)) # register real target, retry
else: raise Prevention
- Register symlink targets as scan folders instead of symlinking from inside allowed roots.
- Test model-tree layout with realpath to confirm containment.
- Expect this 403 on any symlink escape — it is a security guard, not a bug.
When it happens
Trigger: Browsing a path that contains a symlink pointing outside home/scan-folder roots (e.g. ~/models/pointers -> /etc); requested_path matching one root's textual prefix but resolving under a different, unlisted tree.
Common situations: Users organizing models with symlinks to a big external drive; linking datasets into home from system paths; moving scan folders and leaving symlinks behind.
Related errors
- Directory not allowed
- Model path is outside Unsloth storage
- Linked folder is no longer a regular directory
- local cache path must not contain '..' segments
- Invalid block_id: outside upload root
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/33b236e7be69483f.
Report an issue: GitHub.