{"record":{"id":"902222ddce2a8ad2","repo":"unslothai/unsloth","slug":"save-directory-path-components-must-be-255-char","errorCode":null,"errorMessage":"save_directory path components must be <= 255 characters","messagePattern":"save_directory path components must be <= 255 characters","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"warning","filePath":"studio/backend/models/export.py","lineNumber":26,"sourceCode":"from pydantic import BaseModel, Field, field_validator\nfrom typing import List, Optional, Literal, Dict, Any, Union\n\n\ndef _validate_save_directory(value: str) -> str:\n    \"\"\"Validate save_directory — allows absolute paths (user may want a different drive).\"\"\"\n    if value is None:\n        raise ValueError(\"save_directory is required\")\n    raw = str(value).strip()\n    if not raw:\n        raise ValueError(\"save_directory must not be empty\")\n    if \"\\x00\" in raw:\n        raise ValueError(\"save_directory may not contain null bytes\")\n    if any(ch in raw for ch in (\"\\r\", \"\\n\")):\n        raise ValueError(\"save_directory may not contain control characters\")\n    path = Path(raw).expanduser()\n    path_parts = (*path.parts, *PureWindowsPath(raw).parts, *raw.replace(\"\\\\\", \"/\").split(\"/\"))\n    if any(len(part) > 255 for part in path_parts if part not in (\"\", \".\", \"/\", \"\\\\\")):\n        raise ValueError(\"save_directory path components must be <= 255 characters\")\n    if (\n        \"..\" in path.parts\n        or \"..\" in PureWindowsPath(raw).parts\n        or \"..\" in raw.replace(\"\\\\\", \"/\").split(\"/\")\n    ):\n        raise ValueError(\"save_directory may not contain '..' segments\")\n    return raw\n\n\nclass LoadCheckpointRequest(BaseModel):\n    \"\"\"Request for loading a checkpoint into the export backend.\"\"\"\n\n    checkpoint_path: str = Field(..., description = \"Path to the checkpoint directory\")\n    max_seq_length: int = Field(\n        2048,\n        ge = 128,\n        le = 32768,\n        description = \"Maximum sequence length for loading the model\",","sourceCodeStart":8,"sourceCodeEnd":44,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/models/export.py#L8-L44","documentation":"ValueError from _validate_save_directory when any single path component exceeds 255 characters. The limit is checked across POSIX parts, Windows (PureWindowsPath) parts, and naive backslash-split parts, so it catches oversized components regardless of which OS will consume the path — most filesystems (ext4, NTFS, APFS names) cap individual name components near 255 bytes.","triggerScenarios":"Sending a save_directory where one directory or file name component is longer than 255 chars — e.g. a model name + suffix + timestamp concatenated into one directory name, or Windows-style 'C:\\<very long segment>\\out' where the long segment exceeds the cap.","commonSituations":"Auto-generated export dir names built from long model identifiers or full prompt strings; Windows long-path issues; clients that never truncate user-provided names.","solutions":["Shorten the offending component (usually the auto-generated leaf directory name) to under 255 characters.","Split long names across nested subdirectories instead of one giant component.","Truncate generated names client-side with a sane cap (e.g. 100 chars) plus a short hash suffix for uniqueness."],"exampleFix":"# before\nsave_directory = f\"/exports/{model_name}-{full_config_json}\"  # one huge component\n# after\nsave_directory = f\"/exports/{model_name[:80]}-{hashlib.sha1(cfg).hexdigest()[:8]}\"","handlingStrategy":"validation","validationCode":"def save_directory_components_short(payload: dict, limit: int = 255) -> bool:\n    v = payload.get(\"save_directory\")\n    if not isinstance(v, str):\n        return False\n    parts = v.replace(\"\\\\\", \"/\").split(\"/\")\n    return all(len(p) <= limit for p in parts if p not in (\"\", \".\"))","typeGuard":"def is_short_component_path(v: str, limit: int = 255) -> bool:\n    return all(\n        len(p) <= limit\n        for p in v.replace(\"\\\\\", \"/\").split(\"/\")\n        if p not in (\"\", \".\")\n    )","tryCatchPattern":null,"preventionTips":["Cap auto-generated directory names client-side (e.g. 100 chars + short hash).","Prefer nested subdirectories over one long descriptive component.","Remember the check covers both POSIX and Windows interpretations of the string."],"tags":["validation","filesystem","export","http-422","path-length"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}