unslothai/unsloth · warning · RuntimeError
sd-server job queue is full (HTTP 429).
Error message
sd-server job queue is full (HTTP 429).
What it means
The sd-server answered the img_gen submit with HTTP 429, meaning its internal job queue is full. This is backpressure, not a failure: the server intentionally caps concurrent queued jobs and tells the client to stop flooding it. The wrapper surfaces it distinctly so callers can throttle instead of treating it as a dead server.
Source
Thrown at studio/backend/core/inference/sd_cpp_server.py:466
"""
# Already stopped with the cancel event set: report cancellation (route 409), not a generic "server died" 500.
if self._stopped or not self.is_alive():
if cancel_event is not None and cancel_event.is_set():
raise SdCppCancelled("sd-server generation was cancelled.")
raise RuntimeError("sd-server is not running.")
self._step_listener = on_step
job_id: Optional[str] = None
try:
# Submit -> 202 Accepted + job id.
try:
resp = self._client.post(
f"{self.base_url}{_IMG_GEN_PATH}", json = payload, timeout = submit_timeout
)
except (*_TRANSPORT_ERRORS, httpx.TimeoutException) as exc:
raise RuntimeError(self._died_message("img_gen submit", exc)) from exc
if resp.status_code == 429:
raise RuntimeError("sd-server job queue is full (HTTP 429).")
if resp.status_code not in (200, 202):
raise RuntimeError(
f"sd-server img_gen submit -> {resp.status_code}: {resp.text[:500]}"
)
try:
job = resp.json()
except ValueError as exc:
raise RuntimeError(
f"sd-server img_gen returned a non-JSON submit response: {exc}"
) from exc
if not isinstance(job, dict):
raise RuntimeError(
f"sd-server img_gen returned an unexpected submit response type: {type(job)}"
)
job_id = job.get("id")
if not job_id:
raise RuntimeError(f"sd-server img_gen returned no job id: {job}")
View on GitHub (pinned to 203007d190)
Solutions
- Wait for in-flight jobs to finish, then resubmit; respect 429 as a signal to throttle.
- Cap client-side concurrency to the server's queue size (or 1) with a semaphore.
- Batch multiple images into a single job (batch count) instead of many submitted jobs.
Example fix
# before
for prompt in prompts:
threading.Thread(target=server.img_gen, args=(payload(prompt),)).start()
# after
sem = threading.Semaphore(1)
def gen(p):
with sem:
server.img_gen(payload(p)) Defensive patterns
Strategy: retry
Validate before calling
sem = threading.Semaphore(1) # cap concurrent submits at the queue capacity # with sem: server.img_gen(...)
Try / catch
try:
blobs = server.img_gen(payload, ...)
except RuntimeError as e:
if "queue is full" in str(e):
time.sleep(2); blobs = server.img_gen(payload, ...)
raise Prevention
- Limit client-side generation concurrency with a semaphore.
- Batch several images into one job instead of many submits.
- Treat 429 as backpressure: back off, don't hammer.
When it happens
Trigger: Submitting more concurrent img_gen jobs than the server's queue capacity while earlier jobs are still running — parallel batch fan-out from multiple threads or clients.
Common situations: A UI firing several generations at once; an automation script without a concurrency limiter; long-running jobs backing up the queue.
Understand the failure class
- HTTP status errors: handling 4xx and 5xx responses — how to handle 4xx and 5xx responses properly.
Related errors
- failed to spawn sd-server: {self._spawn_error}
- 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 img_gen submit -> {resp.status_code}: {resp.text[:
AI-assisted analysis of unslothai/unsloth@203007d190 (2026-08-15).
Data as JSON: /api/errors/2787e9e52a15be21.
Report an issue: GitHub.