unslothai/unsloth · error · RuntimeError
failed to spawn sd-server: {self._spawn_error}
Error message
failed to spawn sd-server: {self._spawn_error} What it means
Raised when the background thread that spawns the sd-server process records a spawn error (exec failure, missing binary, permission denied). The wrapper disposes the half-started process and surfaces the underlying spawn error string. This happens before any readiness polling — the process never came up.
Source
Thrown at studio/backend/core/inference/sd_cpp_server.py:276
self._process = proc
self.port = port
adopt_pid(proc.pid) # so a global shutdown sweep also reaps it
spawned.set()
self._drain_stdout(proc)
# stdout closed == process exited; reap it so it is not left a zombie.
try:
proc.wait(timeout = 5)
except Exception: # noqa: BLE001
pass
self._stdout_thread = threading.Thread(
target = _own_process, daemon = True, name = "sd-server-owner"
)
self._stdout_thread.start()
spawned.wait()
if self._spawn_error is not None:
self._dispose()
raise RuntimeError(f"failed to spawn sd-server: {self._spawn_error}")
if not self._wait_ready(startup_timeout):
tail = _diagnostic_tail(self._tail, keep = 30)
aborted = self._abort.is_set()
self._kill_locked()
self._dispose()
if aborted:
raise SdCppCancelled("sd-server startup was cancelled.")
raise RuntimeError("sd-server failed to become ready. Last output:\n" + tail[:2000])
def _wait_ready(
self,
timeout: float,
interval: float = 0.5,
) -> bool:
"""Poll ``/v1/models`` until 200; bail early if the process exits.
Upstream binds the port only AFTER the model is loaded, so a 200 here is a true
ready signal (no half-loaded race)."""View on GitHub (pinned to 203007d190)
Solutions
- Read the {self._spawn_error} part — it is the OS-level reason (ENOENT, EACCES, etc.).
- ENOENT/EACCES: restore the binary (`unsloth studio update`) or fix the executable bit and interpreter availability.
- Loader errors: install the paired native libraries the server ships with; do not copy the binary out of its bundle directory.
Defensive patterns
Strategy: try-catch
Validate before calling
binary = find_server_binary()
if binary is None or not os.access(binary, os.X_OK):
raise SystemExit("sd-server binary missing or not executable; run unsloth studio update") Try / catch
try:
server.start()
except RuntimeError as e:
if "failed to spawn" in str(e):
reinstall_runtime(); server.start()
raise Prevention
- Validate the server binary exists and is executable before starting.
- Keep the runtime bundle installed via the updater, not by hand.
- Log the spawn_error fragment — it is the OS-level cause.
When it happens
Trigger: Starting the sd-server wrapper when its binary path is missing, not executable, or fails to exec (bad ELF, wrong architecture, missing shared libraries at exec time).
Common situations: Broken or partial runtime install after a failed update; binary replaced by a non-executable file; running on an OS/arch the build does not support.
Related errors
- sd-server failed to become ready. Last output: {tail[:2000]}
- sd-server is not running.
- sd-server connection lost during img_gen submit
- sd-server job queue is full (HTTP 429).
- sd-server img_gen submit -> {resp.status_code}: {resp.text[:
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/4fcd1270dd90b69d.
Report an issue: GitHub.