unsloth/studio/backend/utils
Nilay ae6b96ba93
Studio: fail fast on out-of-disk instead of a doomed llama.cpp source build (#7420)
* guard llama.cpp prebuilt against out-of-disk instead of doomed source build

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* address review comments on out-of-disk guard

* keep reusable installs and Windows parity in the out-of-disk guard

* preserve the ENOSPC cause when re-raising fallback errors

* catch out-of-disk before the attempt loop and accept all llama-server layouts

* Fix out-of-disk detection gaps and false positives for PR #7420

Follow-ups found while testing the guard against a real ENOSPC (LD_PRELOAD
shim returning errno 28 under a path prefix, real network, real release):

- hydrate_source_tree retried the next mirror after an ENOSPC and only raised
  on the last URL. Both source fallbacks 404 for the published mix commit, so
  the reported cause was HTTP 404 and the run fell through to the source build
  exactly like before the guard. Stop at the first environment-fatal error.
- The 5 GB preflight rejected hosts that install fine. A full CUDA install
  peaks at 0.87 GB, the largest published bundle is 0.77 GB and macOS is
  0.01 GB, so at 3 GB free the install succeeded before and exited 4 after,
  with the source-build fallback suppressed too. It is now advisory, and a
  real ENOSPC still exits 4. This also drops the case where an install
  matching an older release plan was rejected before its reuse check.
- ENOSPC raised inside shutil.copytree arrives as shutil.Error with errno
  None and no __cause__ or __context__, so it was never classified. That path
  covers the hydrated source tree, the runtime overlay and the activation
  fallback copy.
- _causal_chain followed __context__ even when __suppress_context__ was set,
  so `raise ... from None` over an unrelated ENOSPC reported disk full and
  wrongly suppressed the source build.
- TemporaryDirectory now ignores cleanup errors: an rmtree failure on the way
  out replaced the in-flight SystemExit and lost EXIT_NO_SPACE.
- setup.sh skips the arm64 CPU last resort after exit 4; it re-ran the same
  disk-rejected installer and buried the hint under a second error dump.
- The in-app updater turns exit 4 into a readable message instead of
  "installer exited 4" plus a log tail.

Adds tests/studio/install/test_llama_prebuilt_no_space.py covering the
classifier, the advisory warning and the exit codes.

* Fix Python 3.9 breakage and Windows disk-full detection in the out-of-disk guard

Found by running the guard across the whole supported interpreter range
(requires-python is >=3.9,<3.15) and a spoofed [Linux, WSL, macOS, Windows] x
[NVIDIA, AMD, CPU] host matrix.

- TemporaryDirectory(ignore_cleanup_errors = True) is 3.10+, so the previous
  commit raised TypeError at install time on 3.9 and turned a working install
  into a hard failure. Replaced with a scratch_dir() contextmanager built on
  mkdtemp plus rmtree(ignore_errors = True), which behaves the same on every
  supported version.
- getattr(exc, "winerror", None) crashed on 3.9. urllib's HTTPError is an
  OSError that proxies unknown attributes to a wrapped file object and raises
  KeyError, which getattr does not swallow, so any mirror 404 during an install
  would have blown up inside the classifier. Read it defensively instead.
- Classify Windows disk-full by winerror as well as errno. CPython's
  PC/errmap.h maps ERROR_DISK_FULL (112) to ENOSPC but has no case for
  ERROR_HANDLE_DISK_FULL (39), which arrives as EINVAL, so a Windows
  os.replace() onto a full disk read as an ordinary failure and fell through to
  the source build.

Tests cover both winerror codes, a non-disk winerror, and HTTPError alone and
wrapped in a PrebuiltFallback. 116 simulation cases pass on 3.9 through 3.14.

* Classify quota, flattened Windows and validate-install out-of-disk for PR #7420

- EDQUOT counts as out of space: a quota'd home has free blocks this user
  cannot have, so the source build is just as doomed. Reported separately so
  df does not mislead. Confirmed end to end with a real kernel EDQUOT: the
  installer went from 6 retries then a source build (exit 2) to exit 4.
- Match the flattened Windows disk-full text. copytree stringifies each
  per-file OSError, and OSError.__str__ returns early on winerror, so the
  text reads [WinError 112] and never [Errno 28]. Captured on a real NTFS
  volume. Markers are bracketed so WinError 112 does not match WinError 1120.
- --validate-install now exits 4 on a full disk. It caught PrebuiltFallback
  and exited 2 before the classifier ran, and setup.sh answered 2 by deleting
  the GPU build that had just succeeded and starting a CPU rebuild that needs
  more of the space that ran out. Both halves are needed: the call site only
  tested nonzero.

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Tighten comments in the llama.cpp out-of-disk guard

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: danielhanchen <danielhanchen@gmail.com>
2026-07-26 00:11:38 -07:00
..
datasets Studio: add configurable model download location (#7274) 2026-07-23 01:34:38 -07:00
hardware Add Intel XPU support to Unsloth Studio (#4724) 2026-07-24 02:22:07 -03:00
inference Unsloth run/start: per-model recommended sampling and override flags (#7335) 2026-07-23 20:49:54 -07:00
models Studio: add configurable model download location (#7274) 2026-07-23 01:34:38 -07:00
paths Studio: add configurable model download location (#7274) 2026-07-23 01:34:38 -07:00
prebuilt Studio: add local speech-to-text dictation engine (#7095) 2026-07-23 01:39:03 -07:00
security Studio: scan HF cache snapshot loads by their repo id (#7398) 2026-07-24 02:12:00 -07:00
.gitkeep root studio folder 2026-02-02 09:13:49 +00:00
__init__.py Final cleanup 2026-03-12 18:28:04 +00:00
_studio_release_build.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
api_errors.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
cache_cleanup.py Reduce and tighten code comments and docstrings repo-wide (#6095) 2026-06-08 23:09:51 -07:00
client_ip.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
coding_agents.py feat: detect installed coding agent CLIs in Studio settings (#6909) 2026-07-08 05:26:50 -07:00
cpu_threads.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
downsample.py Formatting: ruff line-length 100, kwarg-spacing passes, drop blank after short local imports (#6079) 2026-06-08 04:24:13 -07:00
embedding_model_settings.py Studio: customizable RAG embedding model with HF search, settings tab reorganization (#6800) 2026-07-02 05:26:33 -07:00
helper_precache_settings.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
hf_cache_settings.py Studio: add configurable model download location (#7274) 2026-07-23 01:34:38 -07:00
hf_token_validation.py Studio: validate Hugging Face tokens before use (#7261) 2026-07-20 14:40:14 +01:00
hf_xet_fallback.py Studio: add configurable model download location (#7274) 2026-07-23 01:34:38 -07:00
hidden_models.py Studio: add local speech-to-text dictation engine (#7095) 2026-07-23 01:39:03 -07:00
host_policy.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
lifespan_shutdown.py Studio: make lifespan shutdown resilient to a dead default executor (#6307) 2026-06-15 22:51:46 -07:00
llama_cpp_freshness.py Studio: add local speech-to-text dictation engine (#7095) 2026-07-23 01:39:03 -07:00
llama_cpp_update.py Studio: fail fast on out-of-disk instead of a doomed llama.cpp source build (#7420) 2026-07-26 00:11:38 -07:00
mlx_repair.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
native_path_leases.py Studio: add configurable model download location (#7274) 2026-07-23 01:34:38 -07:00
node_runtime.py Studio: use an isolated Node.js for the frontend build instead of replacing the system Node/npm (#6533) 2026-06-21 21:17:29 -07:00
openai_auto_switch_settings.py persist llama.cpp KV cache across idle auto-unload (slot save/restore) (#7204) 2026-07-20 00:12:42 -07:00
personalization_settings.py studio: persist personalization (profile, avatar, theme) server-side (#6516) 2026-06-22 04:09:48 -07:00
preview_rate_limit.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
preview_sharing_settings.py Studio: require signed capability tokens for /p preview links (#6666) 2026-06-25 21:40:48 -07:00
preview_token.py Studio: require signed capability tokens for /p preview links (#6666) 2026-06-25 21:40:48 -07:00
process_lifetime.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
ssm_runtime.py Auto-install SSM kernels (causal-conv1d, mamba-ssm) for inference loads (#6535) 2026-06-22 04:48:29 -07:00
studio_version.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
subprocess_compat.py Reduce and tighten code comments and docstrings repo-wide (#6095) 2026-06-08 23:09:51 -07:00
training_runs.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
transformers_dtype.py Studio: Fix torch_dtype deprecation warning on startup and ASR load (#6999) 2026-07-13 17:34:25 -03:00
transformers_latest.py Replace standalone Studio wording with Unsloth (#7221) 2026-07-19 00:47:04 -07:00
transformers_version.py Studio: add configurable model download location (#7274) 2026-07-23 01:34:38 -07:00
update_status.py Studio: make code comments and docstrings more succinct (#6029) 2026-06-08 23:07:28 -07:00
upload_limits.py Studio: add local speech-to-text dictation engine (#7095) 2026-07-23 01:39:03 -07:00
utils.py Add Intel XPU support to Unsloth Studio (#4724) 2026-07-24 02:22:07 -03:00
uv_path_safety.py Make _uv_safe_path space-safe on macOS/Linux (#6503) (#6534) 2026-06-24 04:02:24 -07:00
wheel_utils.py Studio: fix flash-attn and torchao install on Blackwell (sm_100+) GPUs (Closes #6961) (#6970) 2026-07-08 06:38:10 -07:00
whisper_cpp_freshness.py Studio: add local speech-to-text dictation engine (#7095) 2026-07-23 01:39:03 -07:00
whisper_cpp_update.py Studio: add local speech-to-text dictation engine (#7095) 2026-07-23 01:39:03 -07:00