unslothai/unsloth · error · InstallerExit
installer exited {returncode}: {tail or 'no output'}
Error message
installer exited {returncode}: {tail or 'no output'} What it means
Raised as InstallerExit(returncode, message) when the prebuilt-installer subprocess finishes with a nonzero exit code. The message embeds the last ~1500 characters of captured installer output (tail_lines) so the underlying installer failure is visible. The finally block already cleans up: cancels the watchdog, unregisters the PID, and stops any components the installer announced but never reported stopped.
Source
Thrown at studio/backend/utils/prebuilt/update_flow.py:414
announced.discard(child_pid)
continue
m = PROGRESS_LINE_RE.search(line)
if m is None:
continue
set_progress(min(float(m.group(1)) / 100.0, 1.0) * DOWNLOAD_PROGRESS_CEILING)
returncode = proc.wait()
finally:
watchdog.cancel()
if proc.poll() is not None:
forget_pid(proc.pid)
# Anything it started and never reported as stopped, whether it timed
# out, exited nonzero, or died mid-line.
_stop_announced()
if timed_out.is_set():
raise RuntimeError(f"installer timed out after {timeout_seconds}s")
if returncode != 0:
tail = "".join(tail_lines).strip()[-1500:]
raise InstallerExit(returncode, f"installer exited {returncode}: {tail or 'no output'}")
def _new_phase_record(spec: dict) -> dict:
"""Initial breakdown entry for one phase of a chained job."""
runnable = spec.get("run") is not None
return {
"state": PHASE_PENDING if runnable else PHASE_SKIPPED,
"reason": None if runnable else spec.get("skip_reason"),
"progress": None,
"to_tag": None,
"reload_required": None,
"message": "",
"error": None,
}
def run_chained_update(phases: list[dict], *, job: dict, job_lock: threading.Lock) -> None:
"""Run update phases in order into one shared job dict (the worker of aView on GitHub (pinned to 203007d190)
Solutions
- Read the embedded tail in the error message — it is the installer's own failure output and pinpoints the exact sub-step that failed.
- Free disk space and verify write permissions on the install target directory.
- Stop other studio processes that may hold locks on files being updated, then re-run the update.
- If the tail shows a checksum/verification failure, clear the cached download and retry to re-fetch the artifact.
Defensive patterns
Strategy: try-catch
Validate before calling
import shutil
def can_install(target_dir) -> tuple[bool, str]:
free = shutil.disk_usage(target_dir).free
if free < REQUIRED_BYTES:
return False, f'insufficient disk space: {free} bytes free'
if not os.access(target_dir, os.W_OK):
return False, 'target directory not writable'
return True, '' Try / catch
try:
run_update_flow(spec)
except InstallerExit as e:
log.error('installer failed rc=%s: %s', e.returncode, e.message)
surface_to_user(e.message) # tail contains the installer's own diagnosis
# do not blind-retry; fix the named cause first Prevention
- Pre-check disk space and write permissions on the install target before starting an update.
- Stop dependent processes before updating so no file locks interrupt the installer.
- Always read the embedded output tail — the installer's own message identifies the failing phase.
When it happens
Trigger: The installer subprocess exits with returncode != 0 — failed integrity check of the downloaded artifact, unwritable target directory, version conflict, missing runtime dependency, or the installer's own internal error. The error message carries the installer's stderr/stdout tail for diagnosis.
Common situations: Corrupted or partially-downloaded installer payload, insufficient disk space or permissions at the install target, an already-running process locking files being replaced, or a version mismatch between the installer bootstrap and the runtime it expects.
Related errors
- installer timed out after {timeout_seconds}s
- Git is required to install the pinned {source_name} source
- Could not install the pinned {source_name} source: {detail}
- No export subprocess running
- Failed to send command to subprocess: {exc}
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/7a8d5d585eb13c7f.
Report an issue: GitHub.