unslothai/unsloth · error · ValueError

path resolution failed: {exc}

Error message

path resolution failed: {exc}

What it means

Raised by _assert_contained in studio/backend/utils/paths/storage_roots.py:384-385 when os.path.realpath() raises OSError while resolving either the candidate path or the storage root. This is an environment-level failure (permissions, stale file handles, path encoding problems), not a validation failure; the error message embeds the underlying OS error.

Source

Thrown at studio/backend/utils/paths/storage_roots.py:384

    if ".." in PureWindowsPath(raw).parts:
        return True
    return ".." in raw.replace("\\", "/").split("/")


def _is_absolute_user_path(path: Path) -> bool:
    expanded = str(path)
    if os.name == "nt":
        return path.is_absolute() and PureWindowsPath(expanded).is_absolute()
    return path.is_absolute() and PurePosixPath(expanded).is_absolute()


def _assert_contained(resolved: Path, root: Path) -> None:
    """Raise ValueError if ``resolved`` realpaths outside ``root``."""
    try:
        resolved_real = Path(os.path.realpath(resolved))
        root_real = Path(os.path.realpath(root))
    except OSError as exc:
        raise ValueError(f"path resolution failed: {exc}") from exc
    try:
        resolved_real.relative_to(root_real)
    except ValueError as exc:
        raise ValueError(
            f"path escapes root: {resolved!s} -> {resolved_real!s} " f"is not under {root_real!s}"
        ) from exc


def resolve_under_root(
    path_value: str | None,
    *,
    root: Path,
    strip_prefixes: tuple[str, ...] = (),
) -> Path:
    """Resolve ``path_value`` and assert the result is under ``root``.

    Absolutes are accepted only if already contained (so pre-resolved
    internal paths re-enter idempotently); schemas reject absolutes upstream.

View on GitHub (pinned to 203007d190)

Solutions

  1. Check the underlying OSError (__cause__) for errno: EACCES -> fix permissions, ELOOP -> break the symlink cycle, ENOENT -> the root may be gone
  2. Verify the storage root exists and is readable before resolving paths under it
  3. Remove or repair symlink loops in or under the root
  4. If the volume is removable, re-mount it and retry the operation

Example fix

# before
path = resolve_under_root(user_input, root=exports_root())

# after
import errno
try:
    path = resolve_under_root(user_input, root=exports_root())
except ValueError as exc:
    cause = exc.__cause__
    if cause and cause.errno == errno.EACCES:
        raise PermissionError(str(cause)) from cause
    raise
Defensive patterns

Strategy: try-catch

Validate before calling

def root_accessible(root) -> bool:
    try:
        root_real = Path(os.path.realpath(root))
        return root_real.exists() and os.access(root_real, os.R_OK | os.X_OK)
    except OSError:
        return False

Try / catch

import errno
try:
    path = resolve_under_root(value, root=root)
except ValueError as exc:
    cause = exc.__cause__
    if isinstance(cause, OSError):
        if cause.errno in (errno.EACCES, errno.EPERM):
            raise HTTPException(403, "storage root not accessible") from exc
        if cause.errno == errno.ELOOP:
            raise HTTPException(400, "symlink loop under storage root") from exc
        raise HTTPException(503, "storage root unavailable") from exc
    raise

Prevention

When it happens

Trigger: resolve_under_root called with a path whose realpath traversal hits an unreadable directory (EACCES), a broken symlink loop (ELOOP), or a path with invalid encoding on the platform. Also when the storage root itself becomes inaccessible (unmounted drive, deleted directory).

Common situations: Storage root on a disconnected network drive or removable volume on Windows; permission changes mid-session; symlink cycles created by users; deeply nested paths exceeding OS limits.

Related errors


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