unslothai/unsloth · error · ValueError
Resume checkpoint must be inside Unsloth outputs.
Error message
Resume checkpoint must be inside Unsloth outputs.
What it means
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.
Source
Thrown at studio/backend/core/training/resume.py:224
str(checkpoint)
for checkpoint in checkpoints
if _checkpoint_step(checkpoint) >= 0
and is_resume_checkpoint_valid(checkpoint, expected_step)
),
None,
)
def normalize_resume_output_dir(path_value: str) -> str:
if _is_foreign_absolute_path(path_value):
raise ValueError("Resume checkpoint uses a path from a different operating system.")
try:
path = resolve_output_dir(path_value)
path.resolve(strict = True)
except (OSError, RuntimeError) as error:
raise ValueError("Resume checkpoint path could not be resolved.") from error
if not _is_under_outputs(path):
raise ValueError("Resume checkpoint must be inside Unsloth outputs.")
return str(path)
def training_run_config(run: dict) -> dict:
raw_config = run.get("config_json")
if isinstance(raw_config, dict):
return raw_config
if not isinstance(raw_config, str) or not raw_config.strip():
return {}
try:
parsed = json.loads(raw_config)
except (json.JSONDecodeError, TypeError):
return {}
return parsed if isinstance(parsed, dict) else {}
def _uses_s3_dataset(run: dict) -> bool:
config = training_run_config(run)View on GitHub (pinned to 203007d190)
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.
Example fix
// before
normalize_resume_output_dir("/tmp/copied-checkpoint")
// after
import shutil
shutil.move("/tmp/copied-checkpoint", str(outputs_root() / "imported-run"))
normalize_resume_output_dir(str(outputs_root() / "imported-run")) Defensive patterns
Strategy: validation
Validate before calling
from utils.paths import outputs_root
from pathlib import Path
def under_outputs(p: str) -> bool:
try:
Path(p).resolve(strict=True).relative_to(outputs_root().resolve(strict=False))
return True
except (OSError, RuntimeError, ValueError):
return False
assert under_outputs(resume_path), "checkpoint must live under outputs root" Try / catch
try:
normalized = normalize_resume_output_dir(path_value)
except ValueError as e:
if "inside Unsloth outputs" in str(e):
# move/copy the checkpoint under outputs_root() and retry
... Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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()).
Related errors
- Resume checkpoint uses a path from a different operating sys
- Resume checkpoint path could not be resolved.
- The Hugging Face cache folder is invalid.
- Choose a folder inside the filesystem or drive root.
- Native path contains invalid characters.
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/40e31f6757ba1c82.
Report an issue: GitHub.