{"record":{"id":"8b631a22df92ff98","repo":"BerriAI/litellm","slug":"braintrust-api-error-e-response-text","errorCode":null,"errorMessage":"Braintrust API error: {e.response.text}","messagePattern":"Braintrust API error: (.+?)","errorType":"http","errorClass":"HTTPException","httpStatus":null,"severity":"error","filePath":"cookbook/litellm_proxy_server/braintrust_prompt_wrapper_server.py","lineNumber":211,"sourceCode":"        )\n\n    # Call Braintrust API\n    braintrust_url = f\"https://api.braintrust.dev/v1/prompt/{prompt_id}\"\n    headers = {\n        \"Authorization\": f\"Bearer {braintrust_token}\",\n        \"Accept\": \"application/json\",\n    }\n    print(f\"headers: {headers}\")\n    print(f\"braintrust_url: {braintrust_url}\")\n    print(f\"braintrust_token: {braintrust_token}\")\n\n    try:\n        async with httpx.AsyncClient(timeout=30.0) as client:\n            response = await client.get(braintrust_url, headers=headers)\n            response.raise_for_status()\n            braintrust_data = response.json()\n    except httpx.HTTPStatusError as e:\n        raise HTTPException(\n            status_code=e.response.status_code,\n            detail=f\"Braintrust API error: {e.response.text}\",\n        )\n    except httpx.RequestError as e:\n        raise HTTPException(\n            status_code=502,\n            detail=f\"Failed to connect to Braintrust API: {str(e)}\",\n        )\n    except json.JSONDecodeError as e:\n        raise HTTPException(\n            status_code=502,\n            detail=f\"Failed to parse Braintrust API response: {str(e)}\",\n        )\n\n    print(f\"braintrust_data: {braintrust_data}\")\n    # Transform the response\n    try:\n        transformed_data = transform_braintrust_response(braintrust_data)","sourceCodeStart":193,"sourceCodeEnd":229,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/cookbook/litellm_proxy_server/braintrust_prompt_wrapper_server.py#L193-L229","documentation":"Raised during iteration of a sync text-completion stream in LiteLLM's OpenAI handler. Even after the stream is established, exceptions can occur while yielding parsed chunks (malformed SSE events, mid-stream connection resets, provider aborts). The for-loop over CustomStreamWrapper catches these and re-wraps them as OpenAIError with status, headers, and text. 'error_text' as the message means the underlying exception lacked a .text attribute and fell back to str(e).","triggerScenarios":"Streaming with stream=True when the connection drops mid-stream, the provider sends an error event partway through, or a chunk fails schema parsing inside CustomStreamWrapper. Also triggered if the stream contains non-JSON SSE data lines.","commonSituations":"Long-running streams over unstable networks; providers that abort generation on content policy triggers; load balancers killing idle SSE connections; partial responses after long generation times.","solutions":["Wrap the entire chunk-consuming loop (not just the call) in try/except for OpenAIError.","Enable num_retries and note that mid-stream retries restart the request; accumulate partial content and decide whether to re-request.","Set explicit stream_timeout to fail fast on stalled streams.","If mid-stream aborts recur, check intermediary proxies for idle-connection timeouts and enable heartbeat/keep-alive."],"exampleFix":"# before\nfor chunk in litellm.text_completion(model=..., prompt=..., stream=True):\n    process(chunk)\n\n# after\ntry:\n    for chunk in litellm.text_completion(model=..., prompt=..., stream=True):\n        process(chunk)\nexcept litellm.exceptions.OpenAIError as e:\n    logger.error(\"stream failed: %s (%s)\", e.message, e.status_code)","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"from litellm.exceptions import OpenAIError\n\ndef is_midstream_failure(e: BaseException) -> bool:\n    return isinstance(e, OpenAIError)","tryCatchPattern":"from litellm.exceptions import OpenAIError\n\npartial = []\ntry:\n    for chunk in litellm.text_completion(model=..., prompt=..., stream=True):\n        partial.append(chunk.choices[0].get(\"text\", \"\"))\nexcept OpenAIError as e:\n    logger.warning(\"stream died after %d chars: %s\", len(\"\".join(partial)), e.message)\n    raise","preventionTips":["Wrap the whole consumption loop, not just the call site, in try/except.","Accumulate partial output so a mid-stream failure is recoverable.","Set stream_timeout and check proxy idle-timeouts for long generations."],"tags":["openai","streaming","mid-stream-error","text-completion","litellm"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}