{"record":{"id":"4b147965f2ce9297","repo":"BerriAI/litellm","slug":"wxo-no-run-id-in-response-run-data","errorCode":null,"errorMessage":"WXO: No run_id in response: {run_data}","messagePattern":"WXO: No run_id in response: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"litellm/a2a_protocol/providers/watsonx_orchestrate/handler.py","lineNumber":157,"sourceCode":"            if status in WatsonxOrchestrateTransformation.TERMINAL_STATES:\n                return result\n\n        raise asyncio.TimeoutError(\n            f\"WXO run '{run_id}' did not reach a terminal state after {max_attempts * interval_s:.0f}s\"\n        )\n\n    @staticmethod\n    async def _get_successful_run_data(\n        run_data: dict[str, Any],\n        base_url: str,\n        auth_headers: dict[str, str],\n        client: AsyncHTTPHandler,\n    ) -> dict[str, Any]:\n        status = run_data.get(\"status\", \"\")\n        if status not in WatsonxOrchestrateTransformation.TERMINAL_STATES:\n            run_id: Final = run_data.get(\"run_id\") or run_data.get(\"id\") or \"\"\n            if not run_id:\n                raise ValueError(f\"WXO: No run_id in response: {run_data}\")\n            run_data = await WatsonxOrchestrateHandler._poll_run(\n                base_url=base_url,\n                run_id=run_id,\n                auth_headers=auth_headers,\n                client=client,\n            )\n            status = run_data.get(\"status\", \"\")\n\n        if status not in WatsonxOrchestrateTransformation.SUCCESS_STATES:\n            raise RuntimeError(f\"WXO run ended with non-success status '{status}': {run_data}\")\n\n        return run_data\n\n    @staticmethod\n    async def _accumulate_wxo_sse_text(response: Any) -> str:\n        accumulated_text = \"\"\n        async for line in response.aiter_lines():\n            if not line.startswith(\"data:\"):","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/a2a_protocol/providers/watsonx_orchestrate/handler.py#L139-L175","documentation":"Raised by LiteLLM's watsonx Orchestrate (WXO) A2A handler when a run-submission response has a non-terminal status but carries neither a 'run_id' nor an 'id' field. The handler needs a run id to poll the run to completion via _poll_run, so without it the flow cannot continue and a ValueError is raised. This almost always indicates an unexpected/changed WXO API response shape (e.g. an error payload that still reports a running status).","triggerScenarios":"Calling an WXO agent through LiteLLM's a2a_protocol where the initial run response dict lacks both 'run_id' and 'id' keys (or both are empty/None) while 'status' is not in TERMINAL_STATES. Typical causes: wrong endpoint/version of watsonx Orchestrate, an error body masquerading as a run, or a proxy returning an HTML error page parsed as JSON.","commonSituations":"watsonx Orchestrate on Cloud Pak for Data upgraded to a version with a changed response schema; cp4d_host/instance_id pointing to the wrong service path so the API returns an unexpected body; authentication middleware returning a JSON error without a run id.","solutions":["Log the full run_data payload (already embedded in the exception message) and compare its keys against the expected WXO run response to spot schema drift or an error body.","Verify cp4d_host, instance_id and wxo_agent_id in litellm_params resolve to the correct watsonx Orchestrate endpoint for your CP4D version.","If your WXO version returns the id under a different key, patch _get_successful_run_data to include that key in the run_id fallback chain and open an issue upstream with the response sample."],"exampleFix":"// before\nrun_id = run_data.get(\"run_id\") or run_data.get(\"id\") or \"\"\nif not run_id:\n    raise ValueError(f\"WXO: No run_id in response: {run_data}\")\n\n// after (also accept alternate id field)\nrun_id = run_data.get(\"run_id\") or run_data.get(\"id\") or run_data.get(\"runId\") or \"\"\nif not run_id:\n    raise ValueError(f\"WXO: No run_id in response: {run_data}\")","handlingStrategy":"try-catch","validationCode":"def has_run_id(run_data: dict) -> bool:\n    return bool(run_data.get(\"run_id\") or run_data.get(\"id\"))","typeGuard":"def is_pollable_wxo_response(run_data: dict) -> bool:\n    status = run_data.get(\"status\", \"\")\n    return status in TERMINAL_STATES or bool(run_data.get(\"run_id\") or run_data.get(\"id\"))","tryCatchPattern":"try:\n    result = await wxo_call(...)\nexcept ValueError as e:\n    if \"No run_id\" in str(e):\n        logger.error(\"WXO response missing run id; dump payload for schema inspection: %s\", e)\n        raise WXOSchemaError(str(e)) from e\n    raise","preventionTips":["Pin the watsonx Orchestrate / CP4D version you test against and re-run integration tests after upgrades.","Log raw WXO responses at DEBUG level in a staging environment to catch schema drift early.","Wrap WXO agent calls in a thin adapter so schema errors surface in one place."],"tags":["watsonx-orchestrate","a2a","schema-drift","api-response"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}