{"record":{"id":"04ca7b67d9056695","repo":"BerriAI/litellm","slug":"e-response-text","errorCode":null,"errorMessage":"{e.response.text}","messagePattern":"\\{e\\.response\\.text\\}","errorType":"exception","errorClass":"Exception","httpStatus":null,"severity":"error","filePath":"litellm/integrations/braintrust_logging.py","lineNumber":250,"sourceCode":"            else:\n                request_data[\"output\"] = output\n\n            if metrics is not None:\n                request_data[\"metrics\"] = metrics\n\n            try:\n                print_verbose(\n                    f\"self.global_braintrust_sync_http_handler.post: {self.global_braintrust_sync_http_handler.post}\"\n                )\n                self.global_braintrust_sync_http_handler.post(\n                    url=f\"{self.api_base}/project_logs/{project_id}/insert\",\n                    json={\"events\": [request_data]},\n                    headers=self.headers,\n                )\n                if self.is_mock_mode:\n                    print_verbose(\"[BRAINTRUST MOCK] Sync event successfully mocked\")\n            except httpx.HTTPStatusError as e:\n                raise Exception(e.response.text)\n        except Exception as e:\n            raise e  # don't use verbose_logger.exception, if exception is raised\n\n    async def async_log_success_event(self, kwargs, response_obj, start_time, end_time):\n        verbose_logger.debug(\"REACHES BRAINTRUST SUCCESS\")\n        try:\n            litellm_call_id: Final = kwargs.get(\"litellm_call_id\")\n            standard_logging_object: Final = kwargs.get(\"standard_logging_object\", {})\n            prompt: Final = {\"messages\": kwargs.get(\"messages\")}\n            output = None\n            choices = []\n            if response_obj is not None and (\n                kwargs.get(\"call_type\", None) == \"embedding\" or isinstance(response_obj, litellm.EmbeddingResponse)\n            ):\n                output = None\n            elif response_obj is not None and isinstance(response_obj, litellm.ModelResponse):\n                output = response_obj[\"choices\"][0][\"message\"].json()\n                choices = response_obj[\"choices\"]","sourceCodeStart":232,"sourceCodeEnd":268,"githubUrl":"https://github.com/BerriAI/litellm/blob/77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8/litellm/integrations/braintrust_logging.py#L232-L268","documentation":"Exception raised in BraintrustLogger.log_success_event when the sync POST to /project_logs/{project_id}/insert returns an HTTP error status — the message is literally just the response body with no context about status code or URL. This is the final telemetry-insert step, so it fires after the project id was already resolved, meaning auth was once valid but now fails or the event payload is rejected.","triggerScenarios":"A successful LLM call being logged when the Braintrust key expired or was revoked mid-process (401), the project_id is stale/deleted (404), the event JSON is malformed or exceeds size limits (400/413), or the org is rate limited (429).","commonSituations":"Keys rotated while long-running proxies stay up; very large logged payloads (big prompts/responses) tripping request-size limits; project deleted in the Braintrust UI while the proxy holds its cached id.","solutions":["Match the embedded response text to a status: re-POST a minimal event with curl using the same key to see the raw status code","Restart the proxy after rotating BRAINTRUST_API_KEY so cached ids/clients are refreshed","If payloads are huge, trim what gets logged or split the event","For 429/5xx bodies, add retry with backoff around telemetry instead of failing the logging path"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"import httpx, os\n\ndef can_insert_events(project_id: str) -> bool:\n    try:\n        r = httpx.post(\n            f\"https://api.braintrust.dev/v1/project_logs/{project_id}/insert\",\n            headers={\"Authorization\": f\"Bearer {os.getenv('BRAINTRUST_API_KEY','')}\"},\n            json={\"events\": []}, timeout=5)\n        return r.status_code < 400 or r.status_code == 400  # 400 on empty is fine; 401/404 is the signal\n    except httpx.RequestError:\n        return False","typeGuard":null,"tryCatchPattern":"try:\n    logger.log_success_event(kwargs, response_obj, start_time, end_time)\nexcept Exception as e:\n    # message is the raw response body — map it: 401 => rotate key; 404 => stale project; 413 => trim payload\n    log_warning(f\"braintrust telemetry dropped: {e}\")  # don't fail the user request","preventionTips":["Restart long-running proxies after credential rotation","Truncate oversized prompts/completions before they reach the callback","Never let telemetry exceptions propagate into user-facing request paths — catch and alert"],"tags":["braintrust","http","event-insert","telemetry","api-authentication"],"backgroundTag":"http-request-failed","analyzedSha":"77b7c6c40c0c5aa5fbcb1d6a1825ac39ca8829b8","analyzedAt":"2026-08-18T11:44:31.656Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}