{"record":{"id":"aa11b247021e55e0","repo":"calesthio/OpenMontage","slug":"prediction-prediction-id-did-not-finish-within","errorCode":null,"errorMessage":"Prediction {prediction_id} did not finish within {timeout:.0f}s (last status: {last_status}). The job may still complete — check {PREDICTION_ENDPOINT}/{prediction_id}","messagePattern":"Prediction (.+?) did not finish within (.+?)s \\(last status: (.+?)\\)\\. The job may still complete — check (.+?)/(.+?)","errorType":"exception","errorClass":"AtlasError","httpStatus":null,"severity":"error","filePath":"tools/atlas_client.py","lineNumber":180,"sourceCode":"        consecutive_transport_errors = 0\n        data = _payload_of(response)\n        last_status = str(data.get(\"status\", \"unknown\")).lower()\n\n        if last_status in TERMINAL_SUCCESS:\n            outputs = data.get(\"outputs\") or []\n            if not outputs:\n                raise AtlasError(\n                    f\"Prediction {prediction_id} reported '{last_status}' but returned no outputs.\"\n                )\n            return data\n        if last_status in TERMINAL_FAILURE:\n            error = data.get(\"error\") or \"no error detail provided\"\n            raise AtlasError(f\"Atlas Cloud generation failed ({last_status}): {error}\")\n\n        time.sleep(interval)\n        elapsed += interval\n\n    raise AtlasError(\n        f\"Prediction {prediction_id} did not finish within {timeout:.0f}s \"\n        f\"(last status: {last_status}). The job may still complete — \"\n        f\"check {PREDICTION_ENDPOINT}/{prediction_id}\"\n    )\n\n\ndef upload_media(file_path: str | Path, api_key: str, timeout: int = 120) -> str:\n    \"\"\"Upload a local file and return the hosted URL Atlas assigns to it.\n\n    Used to turn a local reference image into the `image_url` that image-to-video\n    models expect. Atlas has answered this endpoint with both {\"data\":\n    {\"download_url\": ...}} and a bare {\"url\": ...}, so both shapes are accepted.\n    \"\"\"\n    import requests\n\n    path = Path(file_path)\n    if not path.exists():\n        raise AtlasError(f\"Cannot upload — file not found: {path}\")","sourceCodeStart":162,"sourceCodeEnd":198,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/atlas_client.py#L162-L198","documentation":"Raised by poll when the timeout budget (default 600s) expires while the prediction is still in a non-terminal status. Distinct from a failure: the job may still complete on Atlas's side, so the message includes the direct prediction URL for later inspection. The last observed status is reported to distinguish a stuck queue from active processing.","triggerScenarios":"Long video generations (30s clips at high resolution) exceeding the 600s default; Atlas queue congestion leaving jobs PENDING for extended periods; polling with a large interval so the timeout is hit by a few sleepy iterations while the job is nearly done.","commonSituations":"Premium video models routinely taking 10-20 minutes with default settings; batch submissions saturating the user's concurrency slot so jobs sit queued; timeouts set based on image-generation expectations applied to video.","solutions":["Increase the timeout argument to match the model's realistic render time (video: 15-30 minutes)","Check the included prediction URL — if it later shows succeeded, fetch outputs directly instead of resubmitting and paying twice","Reduce concurrent submissions so your jobs leave the queue faster","For repeated runs, record typical completion times per model and set timeout to 2-3x that"],"exampleFix":"// before\ndata = atlas_client.poll(pid, api_key)\n\n// after\ndata = atlas_client.poll(pid, api_key, timeout=1800.0, interval=5.0)","handlingStrategy":"retry","validationCode":"expected_render_seconds = {\"video-high\": 1200, \"image\": 120}  # per-model baselines\ntimeout = expected_render_seconds.get(model_key, 600) * 1.5","typeGuard":null,"tryCatchPattern":"try:\n    data = atlas_client.poll(pid, api_key, timeout=timeout)\nexcept AtlasError as e:\n    if \"did not finish within\" in str(e):\n        # job may still complete — re-poll the SAME id with a fresh budget\n        data = atlas_client.poll(pid, api_key, timeout=900.0)\n    else:\n        raise","preventionTips":["Never resubmit on this error — the job may finish and bill twice; re-poll the same prediction id","Set timeout to 2-3x the model's typical completion time measured in your own runs","Limit concurrent submissions so jobs don't sit PENDING past your budget"],"tags":["atlas-cloud","timeout","polling","queueing","video-generation"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}