{"record":{"id":"40e31f6757ba1c82","repo":"unslothai/unsloth","slug":"resume-checkpoint-must-be-inside-unsloth-outputs-40e31f","errorCode":null,"errorMessage":"Resume checkpoint must be inside Unsloth outputs.","messagePattern":"Resume checkpoint must be inside Unsloth outputs\\.","errorType":"validation","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"studio/backend/core/training/resume.py","lineNumber":224,"sourceCode":"            str(checkpoint)\n            for checkpoint in checkpoints\n            if _checkpoint_step(checkpoint) >= 0\n            and is_resume_checkpoint_valid(checkpoint, expected_step)\n        ),\n        None,\n    )\n\n\ndef normalize_resume_output_dir(path_value: str) -> str:\n    if _is_foreign_absolute_path(path_value):\n        raise ValueError(\"Resume checkpoint uses a path from a different operating system.\")\n    try:\n        path = resolve_output_dir(path_value)\n        path.resolve(strict = True)\n    except (OSError, RuntimeError) as error:\n        raise ValueError(\"Resume checkpoint path could not be resolved.\") from error\n    if not _is_under_outputs(path):\n        raise ValueError(\"Resume checkpoint must be inside Unsloth outputs.\")\n    return str(path)\n\n\ndef training_run_config(run: dict) -> dict:\n    raw_config = run.get(\"config_json\")\n    if isinstance(raw_config, dict):\n        return raw_config\n    if not isinstance(raw_config, str) or not raw_config.strip():\n        return {}\n    try:\n        parsed = json.loads(raw_config)\n    except (json.JSONDecodeError, TypeError):\n        return {}\n    return parsed if isinstance(parsed, dict) else {}\n\n\ndef _uses_s3_dataset(run: dict) -> bool:\n    config = training_run_config(run)","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/unslothai/unsloth/blob/203007d19051dcd2ae33876786d117c99f6b0368/studio/backend/core/training/resume.py#L206-L242","documentation":"Raised when the resolved resume directory is not located under the Unsloth outputs root. After resolving the path, _is_under_outputs (resume.py:22) checks path.resolve().relative_to(outputs_root()); anything outside that root — /tmp, /data, another user's home — is rejected. The restriction keeps resume operations sandboxed to runs this studio produced, preventing accidental (or malicious) resume from arbitrary directories.","triggerScenarios":"Calling normalize_resume_output_dir('/tmp/my-checkpoint') or any absolute/relative path that resolves outside outputs_root(); symlinks inside outputs that point outside are also caught because _is_under_outputs compares resolved paths.","commonSituations":"User downloads/copies a checkpoint from another machine into /tmp or ~ and tries to resume from there; checkpoint hand-placed in a shared data volume; path traversal attempts like 'outputs/../../etc/checkpoint' (resolved away by resolve()).","solutions":["Move or copy the checkpoint directory under the Unsloth outputs root, then pass its new path.","If the run originally lived under outputs, pass the original path instead of a copy elsewhere.","Check for a misconfigured outputs root (UNSLOTH outputs dir env/config) if the checkpoint really should qualify."],"exampleFix":"// before\nnormalize_resume_output_dir(\"/tmp/copied-checkpoint\")\n// after\nimport shutil\nshutil.move(\"/tmp/copied-checkpoint\", str(outputs_root() / \"imported-run\"))\nnormalize_resume_output_dir(str(outputs_root() / \"imported-run\"))","handlingStrategy":"validation","validationCode":"from utils.paths import outputs_root\nfrom pathlib import Path\n\ndef under_outputs(p: str) -> bool:\n    try:\n        Path(p).resolve(strict=True).relative_to(outputs_root().resolve(strict=False))\n        return True\n    except (OSError, RuntimeError, ValueError):\n        return False\n\nassert under_outputs(resume_path), \"checkpoint must live under outputs root\"","typeGuard":null,"tryCatchPattern":"try:\n    normalized = normalize_resume_output_dir(path_value)\nexcept ValueError as e:\n    if \"inside Unsloth outputs\" in str(e):\n        # move/copy the checkpoint under outputs_root() and retry\n        ...","preventionTips":["Always import external checkpoints into the outputs directory before resuming.","Treat the outputs root as the only sanctioned location for run artifacts.","Never construct resume paths from raw user input without the under-outputs check."],"tags":["path","sandboxing","training-resume","validation"],"backgroundTag":null,"analyzedSha":"203007d19051dcd2ae33876786d117c99f6b0368","analyzedAt":"2026-08-15T02:48:39.846Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}