{"record":{"id":"91b9db4cd9d1a9e0","repo":"MiniMax-AI/skills","slug":"timeout-after-max-wait-s-task-id-task-id-chec","errorCode":null,"errorMessage":"Timeout after {max_wait}s. task_id={task_id}, check manually.","messagePattern":"Timeout after (.+?)s\\. task_id=(.+?), check manually\\.","errorType":"exception","errorClass":"SystemExit","httpStatus":null,"severity":"warning","filePath":"skills/frontend-dev/scripts/minimax_video.py","lineNumber":107,"sourceCode":"        data = resp.json()\n        _check_resp(data)\n\n        status = data.get(\"status\", \"\")\n        file_id = data.get(\"file_id\", \"\")\n\n        if status == \"Success\":\n            if not file_id:\n                raise SystemExit(\"Task succeeded but no file_id returned\")\n            print(f\"  Done! file_id={file_id}\")\n            return file_id\n        elif status == \"Fail\":\n            raise SystemExit(f\"Video generation failed: {json.dumps(data, indent=2)}\")\n        else:\n            print(f\"  [{elapsed}s] Status: {status}...\")\n            time.sleep(interval)\n            elapsed += interval\n\n    raise SystemExit(f\"Timeout after {max_wait}s. task_id={task_id}, check manually.\")\n\n\ndef download_video(file_id: str, output_path: str):\n    \"\"\"Retrieve download URL via file_id and save the video.\"\"\"\n    resp = requests.get(\n        f\"{API_BASE}/files/retrieve\",\n        headers=_headers(),\n        params={\"file_id\": file_id},\n        timeout=30,\n    )\n    resp.raise_for_status()\n    data = resp.json()\n    _check_resp(data)\n\n    download_url = data.get(\"file\", {}).get(\"download_url\", \"\")\n    if not download_url:\n        raise SystemExit(f\"No download_url in response: {json.dumps(data, indent=2)}\")\n","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/MiniMax-AI/skills/blob/60aaae52bb2af8162732751a4332f62a5fef518b/skills/frontend-dev/scripts/minimax_video.py#L89-L125","documentation":"poll_task() looped until elapsed reached max_wait (default 600s) without the status becoming Success or Fail — the job is still Processing/queued. The task is NOT dead; it continues server-side and can be checked later with the task_id.","triggerScenarios":"Long generations (1080P, 10s duration) under load exceeding the default 600s window; high platform concurrency slowing the queue; a too-aggressive poll that exits just before completion; max_wait lowered by the caller.","commonSituations":"First-time 1080P/10s jobs during peak hours; account tier with lower scheduling priority; default 600s too short for the chosen quality; network hiccup making each poll slow so fewer effective checks occur.","solutions":["Raise the budget: re-run with `--max-wait 1200` (or pass max_wait=1200), keeping poll interval reasonable.","Do NOT discard the task_id from the dumped message — re-query GET {API_BASE}/query/video_generation?task_id=... later to resume waiting without re-creating the task.","Lower the work: use 768P/720P and duration 6 to finish faster within the window.","If timeouts are routine, build a resume-capable wrapper that persists task_id and polls across runs."],"exampleFix":"// before: fixed 600s ceiling, task lost on timeout\nraise SystemExit(f\"Timeout after {max_wait}s. task_id={task_id}\")\n\n// after: persist task_id and support resume, raise ceiling\nimport json, pathlib\npathlib.Path(\".video_task\").write_text(task_id)\n# re-run mode: python minimax_video.py --resume <task_id>\nraise TimeoutError(f\"still processing; task_id={task_id} saved for resume\")","handlingStrategy":"retry","validationCode":"import json, pathlib\n\ndef run_video_resumable(prompt, out, max_wait=1200, task_store=pathlib.Path(\".video_task\")):\n    \"\"\"Raise max_wait and persist task_id so a timeout can be resumed.\"\"\"\n    task_id = task_store.read_text() if task_store.exists() else None\n    if not task_id:\n        task_id = create_task(prompt, ...)\n        task_store.write_text(task_id)\n    file_id = poll_task(task_id, interval=10, max_wait=max_wait)  # may raise TimeoutError\n    download_video(file_id, out)\n    task_store.unlink(missing_ok=True)","typeGuard":"def is_processing(status: str) -> bool:\n    \"\"\"True when the task is still in a non-terminal (non-Success/Fail) state.\"\"\"\n    return status not in {\"Success\", \"Fail\"}","tryCatchPattern":"import subprocess, sys\ntimeout = 1200\nwhile True:\n    r = subprocess.run([sys.executable, \"minimax_video.py\", prompt, \"-o\", out, \"--max-wait\", str(timeout)], capture_output=True, text=True)\n    if r.returncode == 0:\n        break\n    if \"Timeout after\" in (r.stderr or r.stdout or \"\"):\n        tid = extract_task_id(r.stdout or r.stderr)  # task_id is in the message\n        timeout = 600  # shorter re-poll window; same task_id continues server-side\n        continue\n    raise RuntimeError(r.stderr or r.stdout)","preventionTips":["Raise --max-wait (e.g. 1200) for 1080P/10s jobs that routinely exceed 600s.","Persist the task_id from the timeout message and resume by re-querying instead of re-creating.","Prefer 768P/720P + duration 6 to stay safely within the default window.","Build a resume-capable wrapper so timeouts don't discard paid work."],"tags":["api","transient","timeout","retry","minimax","video"],"backgroundTag":null,"analyzedSha":"60aaae52bb2af8162732751a4332f62a5fef518b","analyzedAt":"2026-08-13T17:32:34.717Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}