unslothai/unsloth · error · ValueError

dataset path may not contain '..' segments: {raw!r}

Error message

dataset path may not contain '..' segments: {raw!r}

What it means

Raised by resolve_dataset_path() when the expanded path contains a '..' segment. The resolver deliberately blocks parent-directory segments so a caller cannot escape the managed dataset storage roots; this is a path-traversal guard, not an incidental failure.

Source

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

        strip_prefixes = ("exports",),
    )


def resolve_tensorboard_dir(path_value: str | None = None) -> Path:
    return resolve_under_root(
        path_value,
        root = tensorboard_root(),
        strip_prefixes = ("runs", "tensorboard"),
    )


def resolve_dataset_path(path_value: str) -> Path:
    raw = str(path_value or "").strip()
    if "\x00" in raw:
        raise ValueError("dataset path may not contain null bytes")
    path = Path(raw).expanduser()
    if ".." in path.parts:
        raise ValueError(f"dataset path may not contain '..' segments: {raw!r}")
    if path.is_absolute():
        for root_fn in (datasets_root, dataset_uploads_root, recipe_datasets_root):
            try:
                _assert_contained(path, root_fn())
                return path
            except ValueError:
                continue
        raise ValueError(f"dataset path must be relative or under a dataset root: {raw!r}")

    parts = [part for part in Path(path_value).parts if part not in ("", ".")]
    if parts[:2] == ["assets", "datasets"]:
        parts = parts[2:]
    if parts and parts[0] == "uploads":
        cleaned = Path(*parts[1:]) if len(parts) > 1 else Path()
        return dataset_uploads_root() / cleaned
    if parts and parts[0] == "recipes":
        cleaned = Path(*parts[1:]) if len(parts) > 1 else Path()
        return recipe_datasets_root() / cleaned

View on GitHub (pinned to 203007d190)

Solutions

  1. Normalize the path client-side before sending: resolve '..' against a known base so no parent segments remain (e.g. posixpath.normpath on a sandboxed base).
  2. Reject the request with a 400 and surface 'paths may not contain ..' to the user instead of retrying.
  3. If the user genuinely meant a sibling dataset, send the canonical path relative to the dataset root without '..' segments.

Example fix

# before
resolve_dataset_path(request.args['path'])  # '../../etc/passwd'

# after
import posixpath
raw = request.args['path']
if '..' in posixpath.normpath(raw).split('/') and raw.startswith('..'):
    abort(400, 'dataset path may not contain .. segments')
resolve_dataset_path(raw)
Defensive patterns

Strategy: validation

Validate before calling

from pathlib import PurePosixPath

def has_parent_segments(p: str) -> bool:
    return '..' in PurePosixPath(p.replace('\\', '/')).parts

if has_parent_segments(user_path):
    raise HTTPBadRequest('dataset path may not contain .. segments')

Type guard

def is_safe_relative_dataset_path(p: str) -> bool:
    parts = PurePosixPath(p.replace('\\', '/')).parts
    return bool(p) and '\x00' not in p and '..' not in parts

Try / catch

try:
    path = resolve_dataset_path(raw)
except ValueError as e:
    if "'..' segments" in str(e):
        return bad_request('invalid dataset path')  # never retry; it is malicious or a client bug
    raise

Prevention

When it happens

Trigger: Calling resolve_dataset_path() with values like '../secrets.env', 'datasets/../../etc/passwd', or 'a/../b' — note the check runs on Path(raw).expanduser().parts, so a '~' that expands to a path containing '..' also trips it. Both relative and absolute inputs are checked before root containment is evaluated.

Common situations: Frontends composing dataset paths from user-typed text, URL parameters carrying relative paths, or migrations importing legacy paths that used '..' for brevity. Crafted payloads attempting directory traversal through a dataset upload/download endpoint.

Related errors


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