unslothai/unsloth · error · HTTPException
Could not read {os.path.basename(str(target))}
Error message
Could not read {os.path.basename(str(target))} What it means
Raised as a 500 by the browse-folders listing handler when target.iterdir() throws a non-permission OSError on the validated target — the directory enumeration itself failed at the OS level. The detailed exception is logged server-side (with exc_info); the client receives only a basename-scoped 'Could not read' message to avoid leaking paths or raw OS errors.
Source
Thrown at studio/backend/routes/models.py:1821
"browse-folders: rejected path %r (normalized=%s)",
path,
requested_path,
)
raise
entries: list[BrowseEntry] = []
truncated = False
visited = 0
try:
it = target.iterdir()
except PermissionError:
raise HTTPException(
status_code = 403,
detail = f"Permission denied reading {os.path.basename(str(target))}",
)
except OSError as exc:
logger.warning("browse-folders: could not read %s: %s", target, exc, exc_info = True)
raise HTTPException(
status_code = 500,
detail = f"Could not read {os.path.basename(str(target))}",
)
try:
for child in it:
# Bound by *visited*, not *appended*: a cap on len(entries) would never trigger in dirs
# full of files. Counting visits caps worst-case work at ``_BROWSE_ENTRY_CAP``.
visited += 1
if visited > _BROWSE_ENTRY_CAP:
truncated = True
break
try:
if not child.is_dir():
continue
except OSError:
continue
name = child.nameView on GitHub (pinned to 203007d190)
Solutions
- Read the backend log line 'browse-folders: could not read' for the underlying errno.
- Restore the underlying storage (reconnect drive, remount share, reconnect USB) and retry.
- If deleted, refresh the tree from the allowlist root and navigate again.
Defensive patterns
Strategy: fallback
Validate before calling
import os
def readable_now(d: str) -> bool:
try:
next(iter(os.scandir(d)), None)
return True
except OSError:
return False
if not readable_now(target_dir):
entries = load_cached_listing(target_dir) # degrade gracefully
else:
entries = browse(target_dir) Try / catch
try:
entries = browse(dir)
except HTTPError as e:
if e.response.status_code == 500 and 'Could not read' in e.response.json()['detail']:
entries = load_cached_listing(dir)
warn_user('Folder is temporarily unreadable (storage offline?) — showing cached contents.')
else: raise Prevention
- Prefer local/always-mounted storage for model folders.
- Cache last-good listings client-side so transient mount failures degrade instead of erroring.
- Correlate with backend logs ('could not read ... exc_info') to find the underlying errno.
When it happens
Trigger: GET browse-folders?path=<dir> when the directory sits on a disconnected mapped drive, stale NFS/SMB mount, failing disk, or was deleted between the resolve step and the iterdir call.
Common situations: Network share dropped while the browse dialog was open; external USB drive unplugged; disk I/O errors; TOCTOU deletion races.
Related errors
- Could not read {os.path.basename(str(current))}
- Permission denied reading {current.name}
- Invalid path
- Path does not exist: {os.path.basename(requested_path)}
- Credential or configuration directories are not browseable.
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/b0d431e7b139dc43.
Report an issue: GitHub.