{"record":{"id":"ee6258465bc36568","repo":"calesthio/OpenMontage","slug":"suno-generation-timed-out-after-self-max-wait-s","errorCode":null,"errorMessage":"Suno generation timed out after {self._MAX_WAIT}s (taskId: {task_id})","messagePattern":"Suno generation timed out after (.+?)s \\(taskId: (.+?)\\)","errorType":"exception","errorClass":"TimeoutError","httpStatus":null,"severity":"error","filePath":"tools/audio/suno_music.py","lineNumber":273,"sourceCode":"                timeout=30,\n            )\n            response.raise_for_status()\n            result = response.json()\n\n            status = result.get(\"data\", {}).get(\"status\") or result.get(\"status\", \"\")\n\n            if status == \"SUCCESS\":\n                return result.get(\"data\", result)\n            elif status in (\n                \"CREATE_TASK_FAILED\",\n                \"GENERATE_AUDIO_FAILED\",\n                \"SENSITIVE_WORD_ERROR\",\n            ):\n                raise RuntimeError(f\"Suno generation failed with status: {status}\")\n\n            # PENDING, GENERATING, TEXT_SUCCESS, FIRST_SUCCESS — keep polling\n\n        raise TimeoutError(\n            f\"Suno generation timed out after {self._MAX_WAIT}s (taskId: {task_id})\"\n        )\n\n    def _download(self, audio_url: str, inputs: dict[str, Any], api_key: str) -> Path:\n        \"\"\"Download the audio file to the output path.\"\"\"\n        import requests\n\n        output_path = Path(inputs.get(\"output_path\", \"suno_output.mp3\"))\n        output_path.parent.mkdir(parents=True, exist_ok=True)\n\n        response = requests.get(audio_url, timeout=120)\n        response.raise_for_status()\n        output_path.write_bytes(response.content)\n\n        return output_path\n","sourceCodeStart":255,"sourceCodeEnd":289,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/audio/suno_music.py#L255-L289","documentation":"TimeoutError raised by SunoTool._poll when the task does not reach SUCCESS within _MAX_WAIT seconds. The loop polls every _POLL_INTERVAL and accumulates elapsed time; non-terminal statuses (PENDING, GENERATING, TEXT_SUCCESS, FIRST_SUCCESS) keep it waiting until the budget is exhausted. The task may still complete later on the server — only the client gave up.","triggerScenarios":"Long music generations (full songs with lyrics) exceeding the fixed wait budget; Suno queue congestion during peak hours; a task stuck in GENERATING due to a server-side hang.","commonSituations":"Default timeout too short for custom-mode full-song generation; slow Suno proxy adding latency per poll; retrying immediately after a timeout creating duplicate tasks.","solutions":["Increase the tool's max-wait configuration (or pass a longer timeout input) — full-song generation routinely takes several minutes.","Extract the taskId from the error message and re-poll it later instead of submitting a new (billable) generation.","Check the Suno gateway status/queue; if congested, retry at an off-peak time.","Distinguish this TimeoutError from RuntimeError in callers so a timeout triggers resume/poll-again logic rather than a full resubmit."],"exampleFix":"// before\nresult = tool.run({\"prompt\": lyrics, \"output_path\": \"song.mp3\"})  # TimeoutError after MAX_WAIT\n\n// after (catch and resume polling by taskId)\ntry:\n    result = tool.run(inputs)\nexcept TimeoutError as e:\n    task_id = extract_task_id(str(e))\n    result = tool.resume_task(task_id, inputs)  # poll existing task again","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    result = tool.run(inputs)\nexcept TimeoutError as e:\n    task_id = str(e).split(\"taskId: \")[-1].rstrip(\")\")\n    result = poll_existing_task(task_id, inputs)  # resume, do not resubmit","preventionTips":["Set the wait budget above the worst-case full-song generation time","Persist the taskId on submission so a timeout can be resumed instead of re-billed"],"tags":["suno","timeout","polling","music"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}