unslothai/unsloth · error · ValueError
save_directory may not contain '..' segments
Error message
save_directory may not contain '..' segments
What it means
ValueError from _validate_save_directory when the path contains '..' segments in any interpretation — POSIX parts, Windows PureWindowsPath parts, or naive backslash/slash splitting. This blocks directory traversal: export destinations must be explicit paths, not relative escapes, and the redundant multi-view check closes Windows/POSIX mismatch loopholes (e.g. '..\..\evil' on a Linux server that later ships the path to Windows).
Source
Thrown at studio/backend/models/export.py:32
if value is None:
raise ValueError("save_directory is required")
raw = str(value).strip()
if not raw:
raise ValueError("save_directory must not be empty")
if "\x00" in raw:
raise ValueError("save_directory may not contain null bytes")
if any(ch in raw for ch in ("\r", "\n")):
raise ValueError("save_directory may not contain control characters")
path = Path(raw).expanduser()
path_parts = (*path.parts, *PureWindowsPath(raw).parts, *raw.replace("\\", "/").split("/"))
if any(len(part) > 255 for part in path_parts if part not in ("", ".", "/", "\\")):
raise ValueError("save_directory path components must be <= 255 characters")
if (
".." in path.parts
or ".." in PureWindowsPath(raw).parts
or ".." in raw.replace("\\", "/").split("/")
):
raise ValueError("save_directory may not contain '..' segments")
return raw
class LoadCheckpointRequest(BaseModel):
"""Request for loading a checkpoint into the export backend."""
checkpoint_path: str = Field(..., description = "Path to the checkpoint directory")
max_seq_length: int = Field(
2048,
ge = 128,
le = 32768,
description = "Maximum sequence length for loading the model",
)
load_in_4bit: bool = Field(
True,
description = "Whether to load the model in 4-bit quantization",
)
trust_remote_code: bool = Field(View on GitHub (pinned to 203007d190)
Solutions
- Send an explicit destination path without '..' — resolve relative paths client-side first (os.path.abspath / path.resolve()) before including them in the payload.
- In the client, reject any user input containing '..' components for destination fields.
- If a traversal attempt shows up in server logs, treat it as a security signal and audit the calling client.
Example fix
# before
payload = {"save_directory": "../../shared/exports"}
# after
payload = {"save_directory": str((BASE_DIR / "exports" / name).resolve())} Defensive patterns
Strategy: validation
Validate before calling
def save_directory_no_traversal(payload: dict) -> bool:
v = payload.get("save_directory")
if not isinstance(v, str):
return False
parts = v.replace("\\", "/").split("/")
return ".." not in parts Type guard
def is_traversal_free_path(v: str) -> bool:
return ".." not in v.replace("\\", "/").split("/") Prevention
- Resolve paths client-side (os.path.abspath / Path.resolve()) before sending.
- Reject any '..' in user-supplied destination fields at the UI layer.
- Audit server logs for this message — occurrences indicate probing or a client joining relative paths unsafely.
When it happens
Trigger: Sending save_directory like '../../etc', 'outputs/../../home/user/.ssh', or '..\..\C:\Windows' — accidental relative-path joining in clients, or deliberate traversal attempts against the export endpoint.
Common situations: Clients that join a user-supplied relative path onto a base directory without normalizing; security testing; path fields sourced from unvalidated URL parameters.
Related errors
- save_directory may not contain null bytes
- save_directory may not contain control characters
- dataset path may not contain null bytes
- dataset path may not contain '..' segments: {raw!r}
- save_directory is required
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/7e3b3b1c4ab42ee2.
Report an issue: GitHub.