calesthio/OpenMontage · warning · ComfyUIError
Prompt {prompt_id} did not complete within {timeout}s (webso
Error message
Prompt {prompt_id} did not complete within {timeout}s (websocket wait). The job was not cancelled — resume with resume_prompt_id={prompt_id!r} and a longer timeout. What it means
ComfyUIError raised by wait_ws when the websocket wait loop ends without receiving the 'executing node=None' completion frame for this prompt within the timeout. Before raising, it makes a best-effort history probe (_history_entry_if_reachable): if the job actually finished, the entry is returned instead. Only when history is inconclusive does it raise, embedding resume_prompt_id so the caller can continue waiting without resubmitting — the job was not cancelled.
Source
Thrown at tools/_comfyui/client.py:328
if data.get("prompt_id") not in (None, prompt_id):
continue # another job sharing this connection
msg_type = message.get("type")
if msg_type == "progress":
if on_progress:
on_progress(data)
elif msg_type == "execution_error":
raise ComfyUIError(f"Execution error: {data}", prompt_id=prompt_id)
elif msg_type == "executing" and data.get("node") is None:
finished = True
break
finally:
conn.close()
if not finished:
entry = self._history_entry_if_reachable(prompt_id)
if entry is not None:
return entry
raise ComfyUIError(
f"Prompt {prompt_id} did not complete within {timeout}s "
f"(websocket wait). The job was not cancelled — resume with "
f"resume_prompt_id={prompt_id!r} and a longer timeout.",
prompt_id=prompt_id,
)
entry = self._history_entry(prompt_id)
if entry is None:
raise ComfyUIError(
f"No history entry for {prompt_id} after completion",
prompt_id=prompt_id,
)
return entry
def _wait(
self,
prompt_id: str,
*,View on GitHub (pinned to 95e1c3d0ab)
Solutions
- Resume with the embedded resume_prompt_id and a longer timeout — do not resubmit a fresh job
- If behind a proxy, raise its websocket read/idle timeout or connect directly to ComfyUI's port
- Check GET /history/{prompt_id} once manually to see whether the job already completed
- Increase timeout up front for known-heavy workflows
Example fix
# before entry = client.wait_ws(prompt_id, timeout=600) # after entry = client.wait_ws(prompt_id, timeout=3600) # or resume later: client.generate(..., resume_prompt_id=prompt_id, timeout=3600)
Defensive patterns
Strategy: retry
Validate before calling
import requests
def history_ready(server_url: str, prompt_id: str) -> bool:
try:
return prompt_id in requests.get(f"{server_url}/history/{prompt_id}", timeout=5).json()
except requests.RequestException:
return False Try / catch
try:
entry = client.wait_ws(prompt_id, timeout=600)
except ComfyUIError as e:
if "(websocket wait)" in str(e):
pid = getattr(e, "prompt_id", None)
# job not cancelled — resume instead of resubmitting
entry = client.poll(pid, timeout=3600) if pid else None
if entry is None:
raise
else:
raise Prevention
- Raise proxy websocket idle timeouts or bypass the proxy for /ws
- Size timeout to worst-case job duration, not average
- On timeout, always resume by prompt_id rather than resubmitting
When it happens
Trigger: Long jobs exceeding the websocket timeout; the socket dropped/reconnected mid-run (server restart, proxy idle timeout); ComfyUI finished the job but the completion frame was missed and history was momentarily unreachable.
Common situations: Nginx/proxy websocket idle timeouts killing the connection during a 30-minute video job; ComfyUI restarted under load; default timeout too small for heavy local workflows; shared server where many jobs compete.
Understand the failure class
- Timeouts: ETIMEDOUT, deadlines, and hung requests — what actually expires when a request times out.
Related errors
- Prompt {prompt_id} did not complete within {timeout}s. The j
- Execution error: {data}
- Checkpoint artifacts must be a dictionary
- Backlot server did not become healthy
- Node errors: {json.dumps(data['node_errors'])}
AI-assisted analysis of calesthio/OpenMontage@95e1c3d0ab (2026-08-15).
Data as JSON: /api/errors/2158b758e86a8a64.
Report an issue: GitHub.