{"record":{"id":"1a96c9fe670e7f03","repo":"calesthio/OpenMontage","slug":"prompt-prompt-id-did-not-complete-within-timeou","errorCode":null,"errorMessage":"Prompt {prompt_id} did not complete within {timeout}s. The job is very likely still running on the ComfyUI server (local/custom workflows on modest GPUs routinely exceed the client wait) — it was not cancelled. Poll GET {{server_url}}/history/{prompt_id} directly, or call generate()/execute() again with a longer timeout and this prompt_id to resume waiting without resubmitting.","messagePattern":"Prompt (.+?) did not complete within (.+?)s\\. The job is very likely still running on the ComfyUI server \\(local/custom workflows on modest GPUs routinely exceed the client wait\\) — it was not cancelled\\. Poll GET (.+?)\\}/history/(.+?) directly, or call generate\\(\\)/execute\\(\\) again with a longer timeout and this prompt_id to resume waiting without resubmitting\\.","errorType":"exception","errorClass":"ComfyUIError","httpStatus":null,"severity":"warning","filePath":"tools/_comfyui/client.py","lineNumber":213,"sourceCode":"        if not prompt_id:\n            raise ComfyUIError(f\"No prompt_id in response: {data}\")\n        return prompt_id\n\n    def poll(\n        self,\n        prompt_id: str,\n        *,\n        timeout: int = 600,\n        interval: int = 5,\n    ) -> dict:\n        \"\"\"Block until *prompt_id* finishes.  Returns the history entry.\"\"\"\n        deadline = time.time() + timeout\n        while time.time() < deadline:\n            entry = self._history_entry(prompt_id)\n            if entry is not None:\n                return entry\n            time.sleep(interval)\n        raise ComfyUIError(\n            f\"Prompt {prompt_id} did not complete within {timeout}s. \"\n            f\"The job is very likely still running on the ComfyUI server \"\n            f\"(local/custom workflows on modest GPUs routinely exceed the \"\n            f\"client wait) — it was not cancelled. Poll \"\n            f\"GET {{server_url}}/history/{prompt_id} directly, or call \"\n            f\"generate()/execute() again with a longer timeout and this \"\n            f\"prompt_id to resume waiting without resubmitting.\",\n            prompt_id=prompt_id,\n        )\n\n    def _history_entry(self, prompt_id: str) -> dict | None:\n        \"\"\"Return a completed history entry, or ``None`` while it is absent.\"\"\"\n        resp = requests.get(f\"{self.server_url}/history/{prompt_id}\", timeout=10)\n        resp.raise_for_status()\n        entry = resp.json().get(prompt_id)\n        if entry is None:\n            return None\n        status = entry.get(\"status\", {})","sourceCodeStart":195,"sourceCodeEnd":231,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/_comfyui/client.py#L195-L231","documentation":"ComfyUIError raised by poll() when the prompt has not produced a completed history entry within the client-side timeout (default 600s, 5s interval). Crucially the job is NOT cancelled server-side — ComfyUI keeps executing; the error message carries prompt_id so you can resume waiting via generate()/execute() with the same prompt_id instead of resubmitting (and paying GPU time again). This is a client patience limit, not a server failure.","triggerScenarios":"Polling a heavy local workflow (SDXL/high-res video, custom multi-stage graphs) on a modest GPU where 600s isn't enough; queue congestion because other jobs are ahead; long model-load times on first run when weights download or swap from disk.","commonSituations":"Default 600s timeout used for video-generation workflows that take 20-40 min; ComfyUI on a shared box with a deep queue; cold start downloading a 6GB checkpoint inside the job.","solutions":["Retry the call with the SAME prompt_id and a longer timeout — the job continues server-side (e.g. timeout=3600)","Poll GET {server_url}/history/{prompt_id} directly to watch progress without the client","Pre-warm models (run a tiny job first) and keep queues empty before long generations","Raise the timeout argument up front for known-heavy workflows instead of relying on the 600s default"],"exampleFix":"# before\nentry = client.poll(prompt_id)  # default timeout=600\n\n# after\nentry = client.poll(prompt_id, timeout=3600, interval=10)","handlingStrategy":"retry","validationCode":"import requests\ndef queue_depth(server_url: str) -> int:\n    q = requests.get(f\"{server_url}/queue\", timeout=5).json()\n    return len(q.get(\"queue_running\", [])) + len(q.get(\"queue_pending\", []))\nif queue_depth(server_url) > 2:\n    print(\"warning: ComfyUI queue is deep; long waits likely\")","typeGuard":null,"tryCatchPattern":"def poll_with_resume(client, prompt_id, timeouts=(600, 1800, 7200)):\n    for t in timeouts:\n        try:\n            return client.poll(prompt_id, timeout=t)\n        except ComfyUIError as e:\n            if \"did not complete within\" not in str(e):\n                raise\n    raise RuntimeError(\"job never completed; inspect server manually\")","preventionTips":["Pass timeout proportional to expected job cost (video ≫ images)","Reuse prompt_id on resume — never resubmit a still-running job","Pre-warm model loads with a tiny job first","Monitor GET /history/{prompt_id} out-of-band for long runs"],"tags":["comfyui","timeout","long-running","gpu"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}