{"record":{"id":"0bb8fd2db198c065","repo":"BerriAI/litellm","slug":"res-json-get-error-res-text","errorCode":null,"errorMessage":"res.json().get(\"error\", res.text)","messagePattern":"res\\.json\\(\\)\\.get\\(\"error\", res\\.text\\)","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/integrations/deepeval/api.py","lineNumber":98,"sourceCode":"\n    def send_request(self, method: HttpMethods, endpoint: Endpoints, body=None, params=None):\n        url: Final = f\"{self.base_api_url}{endpoint.value}\"\n        res: Final = self._http_request(\n            method=method.value,\n            url=url,\n            headers=self._headers,\n            json=body,\n            params=params,\n        )\n\n        if res.status_code == 200:\n            try:\n                return res.json()\n            except ValueError:\n                return res.text\n        else:\n            verbose_logger.debug(res.json())\n            raise Exception(res.json().get(\"error\", res.text))\n\n    async def a_send_request(self, method: HttpMethods, endpoint: Endpoints, body=None, params=None):\n        if method != HttpMethods.POST:\n            raise Exception(\"Only POST requests are supported\")\n\n        url: Final = f\"{self.base_api_url}{endpoint.value}\"\n        try:\n            await self.async_http_handler.post(\n                url=url,\n                headers=self._headers,\n                json=body,\n                params=params,\n            )\n        except httpx.HTTPStatusError as e:\n            raise Exception(f\"DeepEval logging error: {e.response.text}\")\n        except Exception as e:\n            raise e\n","sourceCodeStart":80,"sourceCodeEnd":116,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/integrations/deepeval/api.py#L80-L116","documentation":"send_request treats any status other than exactly 200 as fatal, raising an Exception whose message is the server's JSON \"error\" field (falling back to raw body text). Grounded caveat: in this vendored copy _http_request returns None (missing return statement), so `res.status_code` raises AttributeError before this line can ever execute — the branch is currently dead code until the client is fixed to return the response.","triggerScenarios":"After patching the missing return: Confident AI answering 201/202 or any 4xx/429/5xx; a payload the server accepts-but-rejects (400 with an \"error\" JSON body); rate limiting during batch trace uploads.","commonSituations":"Server contract drift (201 Created responses), expired keys, quota exhaustion — plus, today, simply reaching this code path via the un-patched vendored client.","solutions":["First fix the vendored client so _http_request returns the httpx response (without this, res is always None)","Log res.status_code and the parsed body before raising to capture the server's reason","For auth errors re-check CONFIDENT_API_KEY; for 429 add backoff/batching; for 201-style replies widen the success check"],"exampleFix":"# before\nraise Exception(res.json().get(\"error\", res.text))\n\n# after\nif res.status_code >= 400:\n    try:\n        msg = res.json().get(\"error\", res.text)\n    except ValueError:\n        msg = res.text\n    raise Exception(f\"DeepEval API {res.status_code}: {msg}\")\nreturn res.json() if res.headers.get(\"content-type\", \"\").startswith(\"application/json\") else res.text","handlingStrategy":"try-catch","validationCode":"# Nothing to pre-validate server-side; guard the client contract instead:\nfrom litellm.integrations.deepeval.api import HttpMethods\n\ndef valid_send_args(method, endpoint) -> bool:\n    return method is HttpMethods.POST and hasattr(endpoint, \"value\")","typeGuard":null,"tryCatchPattern":"try:\n    result = api.send_request(HttpMethods.POST, Endpoints.TRACING_ENDPOINT, body=body)\nexcept Exception as e:\n    body = str(e)\n    if \"error\" in body or body.startswith(\"{\"):\n        litellm.verbose_logger.warning(\"confident-ai rejected payload: %s\", body)\n    raise","preventionTips":["Patch the vendored _http_request to return the response before relying on status handling","Never assume exactly-200 semantics on third-party APIs; log status codes explicitly","Keep the deepeval dependency pinned and diff vendored copies on upgrade"],"tags":["deepeval","http-status","api-client","error-body","dead-code"],"backgroundTag":"http-error-response","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","schemaVersion":2},"datasetVersion":"2026-08-24T22:17:12.610Z"}