{"record":{"id":"4fae25381669e195","repo":"calesthio/OpenMontage","slug":"atlas-cloud-did-not-return-a-prediction-id-str-d","errorCode":null,"errorMessage":"Atlas Cloud did not return a prediction id: {str(data)[:500]}","messagePattern":"Atlas Cloud did not return a prediction id: (.+?)","errorType":"exception","errorClass":"AtlasError","httpStatus":null,"severity":"error","filePath":"tools/atlas_client.py","lineNumber":123,"sourceCode":"def submit(endpoint: str, payload: dict[str, Any], api_key: str, timeout: int = 60) -> str:\n    \"\"\"Submit a generation request and return its prediction id.\"\"\"\n    import requests\n\n    try:\n        response = requests.post(\n            endpoint, headers=_headers(api_key), json=payload, timeout=timeout\n        )\n    except AtlasError:\n        raise\n    except Exception as exc:  # noqa: BLE001\n        raise AtlasError(f\"Could not reach Atlas Cloud at {endpoint}: {exc}\") from exc\n\n    _raise_for_status(response, \"Atlas Cloud submission\")\n    data = _payload_of(response)\n\n    prediction_id = data.get(\"id\")\n    if not prediction_id:\n        raise AtlasError(f\"Atlas Cloud did not return a prediction id: {str(data)[:500]}\")\n    return str(prediction_id)\n\n\ndef poll(\n    prediction_id: str,\n    api_key: str,\n    interval: float = 3.0,\n    timeout: float = 600.0,\n    request_timeout: int = 30,\n) -> dict[str, Any]:\n    \"\"\"Poll a prediction until it terminates. Returns the final `data` object.\n\n    Raises AtlasError on reported failure or when `timeout` seconds elapse.\n    \"\"\"\n    import requests\n\n    url = f\"{PREDICTION_ENDPOINT}/{prediction_id}\"\n    elapsed = 0.0","sourceCodeStart":105,"sourceCodeEnd":141,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/atlas_client.py#L105-L141","documentation":"Raised by submit when the parsed Atlas envelope succeeds (HTTP ok, code 200 or absent) but the data object contains no id field. The prediction id is required to poll for the result, so the flow cannot continue. The truncated payload is included to show what the server actually returned.","triggerScenarios":"Submitting to an endpoint that returns a different shape (e.g. a synchronous result with outputs but no queued prediction); an endpoint URL typo landing on a non-generation route; Atlas contract drift renaming id to prediction_id or nesting it.","commonSituations":"Using a documentation example endpoint string that differs from the real generate endpoint; copy-pasting between image and video API versions with different envelopes; model routes that execute synchronously and skip the queue.","solutions":["Log the included payload snippet and check where the id lives (renamed or nested field)","Confirm the endpoint argument matches the documented generation endpoint for the exact model","If the model runs synchronously, use the direct response handling instead of submit+poll","Update the client for the current API version if the field was renamed"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":"def submit_response_has_id(data: dict) -> bool:\n    return bool(data.get(\"id\"))","tryCatchPattern":null,"preventionTips":["Use the exact documented endpoint string for the model you submit to","Pin the client version matched to the Atlas API version you tested against","Log the payload snippet when this fires to spot renamed id fields quickly"],"tags":["atlas-cloud","api-contract","submit","validation"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}