unslothai/unsloth · error · RuntimeError
sd-cli timed out after {timeout}s
Error message
sd-cli timed out after {timeout}s What it means
The sd-cli subprocess watchdog kills the process tree and raises this when the monotonic deadline (start + timeout) passes while the process is still running. The loop polls every 100ms and distinguishes timeout from cancellation (cancel raises SdCppCancelled instead). A None timeout disables the check entirely.
Source
Thrown at studio/backend/core/inference/sd_cpp_engine.py:795
for rec in iter_sd_cpp_records(proc.stdout):
line_q.put(rec)
finally:
line_q.put(None)
reader = threading.Thread(target = _drain, daemon = True)
reader.start()
deadline = None if timeout is None else time.monotonic() + float(timeout)
stdout_done = False
try:
while True:
# Cancellation: kill the process tree and signal cancelled, not failure.
if cancel_event is not None and cancel_event.is_set() and proc.poll() is None:
_terminate(proc)
raise SdCppCancelled("sd-cli generation was cancelled.")
if deadline is not None and time.monotonic() >= deadline and proc.poll() is None:
_terminate(proc)
raise RuntimeError(f"sd-cli timed out after {timeout}s")
try:
line = line_q.get(timeout = 0.1)
except queue.Empty:
if proc.poll() is not None and stdout_done:
break
continue
if line is None:
stdout_done = True
if proc.poll() is not None:
break
continue
tail.append(line)
if len(tail) > 40:
tail.pop(0)
if on_log is not None:
on_log(line)
ret = proc.wait(timeout = 5.0)
finally:View on GitHub (pinned to 203007d190)
Solutions
- Pass a larger (or None) timeout to the generate call.
- Reduce steps, resolution, or batch size so the run fits the budget.
- Free the machine (close competing GPU/CPU jobs) or move to the server path, which streams progress and handles long runs better.
Example fix
# before engine.generate(files, params, output_path=out, timeout=60) # after engine.generate(files, params, output_path=out, timeout=1800)
Defensive patterns
Strategy: retry
Validate before calling
estimated = steps * (width * height) / 500_000 # rough seconds heuristic timeout = max(timeout, estimated * 4)
Try / catch
try:
engine.generate(files, params, output_path=out, timeout=t)
except RuntimeError as e:
if "timed out" in str(e) and t is not None:
engine.generate(files, params, output_path=out, timeout=t * 3)
raise Prevention
- Scale timeout with steps x resolution, not a fixed constant.
- Prefer the server path for long runs; it reports progress and cancels cleanly.
- Pass timeout=None for unattended batch jobs you monitor externally.
When it happens
Trigger: Calling the CLI generate with a finite timeout smaller than the actual generation time — big resolutions, many steps, LoRA materialization, or CPU-only execution easily exceed tight defaults.
Common situations: Default timeout on slow hardware; steps/resolution raised without raising timeout; heavy machine load (another model training) starving the CLI of CPU/GPU.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- sd-cli exited {ret}. Last output: {"\n".join(tail[-12:])}
- sd-cli reported success but no image at {out}. Last output:
- sd-server failed to become ready. Last output: {tail[:2000]}
- sd-server returned {len(blobs)} of {count} requested images
- The stable-diffusion.cpp binary was replaced by an install f
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/d8c06d044f8919f7.
Report an issue: GitHub.