{"record":{"id":"ac8e01cac394ce12","repo":"calesthio/OpenMontage","slug":"atlas-cloud-returned-an-unexpected-data-field","errorCode":null,"errorMessage":"Atlas Cloud returned an unexpected 'data' field: {str(data)[:500]}","messagePattern":"Atlas Cloud returned an unexpected 'data' field: (.+?)","errorType":"exception","errorClass":"AtlasError","httpStatus":null,"severity":"error","filePath":"tools/atlas_client.py","lineNumber":94,"sourceCode":"        body = response.json()\n    except Exception as exc:  # noqa: BLE001 - surface the raw text, not a parse trace\n        text = getattr(response, \"text\", \"\")\n        raise AtlasError(f\"Atlas Cloud returned a non-JSON response: {text[:500]}\") from exc\n\n    if not isinstance(body, dict):\n        raise AtlasError(f\"Atlas Cloud returned an unexpected payload: {str(body)[:500]}\")\n\n    code = body.get(\"code\")\n    if code is not None and int(code) != 200:\n        message = body.get(\"message\") or body.get(\"error\") or str(body)[:500]\n        raise AtlasError(f\"Atlas Cloud error (code {code}): {message}\")\n\n    data = body.get(\"data\")\n    if data is None:\n        # uploadMedia historically answered with a bare {\"url\": ...}.\n        return body\n    if not isinstance(data, dict):\n        raise AtlasError(f\"Atlas Cloud returned an unexpected 'data' field: {str(data)[:500]}\")\n    return data\n\n\ndef _raise_for_status(response: Any, context: str) -> None:\n    status = getattr(response, \"status_code\", 200)\n    if status >= 400:\n        text = getattr(response, \"text\", \"\")\n        raise AtlasError(f\"{context} failed with HTTP {status}: {text[:500]}\")\n\n\ndef 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        )","sourceCodeStart":76,"sourceCodeEnd":112,"githubUrl":"https://github.com/calesthio/OpenMontage/blob/95e1c3d0ab93482159818560f6a8c8e866b9139f/tools/atlas_client.py#L76-L112","documentation":"Raised by _payload_of when the envelope has code 200 but its data field is not a JSON object (array, string, number, or boolean). This catches servers that acknowledge success yet attach a malformed data payload, breaking the downstream dict access (data.get('id'), data.get('status')). The offending value's first 500 characters are included.","triggerScenarios":"A poll returning data as a list of output URLs; a submit response with data as a bare prediction-id string; API version drift where data became a nested array per output format.","commonSituations":"Atlas API evolution changing the data shape; middleboxes rewriting responses; endpoints that legitimately return non-object data being routed through this generic client.","solutions":["Log the included snippet to identify the actual shape, then compare with current Atlas API docs","If the shape is a legitimate new format, update the client handling for that endpoint instead of relying on the generic parser","Pin/request a stable API version header if Atlas exposes one","Report to Atlas support if HTTP 200 + code 200 + non-dict data appears on their standard endpoints"],"exampleFix":null,"handlingStrategy":"validation","validationCode":null,"typeGuard":"def has_dict_data(body: dict) -> bool:\n    data = body.get(\"data\")\n    return data is None or isinstance(data, dict)","tryCatchPattern":null,"preventionTips":["Contract-test the parsed data shape in CI against a recorded response fixture","Track Atlas API changelog for data-field changes","Log the raw envelope once when this fires to capture the actual shape for the fix"],"tags":["atlas-cloud","json","api-contract","validation"],"backgroundTag":null,"analyzedSha":"95e1c3d0ab93482159818560f6a8c8e866b9139f","analyzedAt":"2026-08-15T06:31:20.014Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}