{"record":{"id":"a1c1a5eed10b52a1","repo":"BerriAI/litellm","slug":"str-response-read","errorCode":null,"errorMessage":"str(response.read())","messagePattern":"str\\(response\\.read\\(\\)\\)","errorType":"http","errorClass":"LangGraphError","httpStatus":null,"severity":"error","filePath":"litellm/llms/langgraph/chat/transformation.py","lineNumber":312,"sourceCode":"        )\n        from litellm.utils import CustomStreamWrapper\n\n        if client is None or not isinstance(client, HTTPHandler):\n            client = _get_httpx_client(params={})\n\n        verbose_logger.debug(\"Making sync streaming request to: %s\", api_base)\n\n        # Make streaming request\n        response: Final = client.post(\n            api_base,\n            headers=headers,\n            data=json.dumps(data),\n            stream=True,\n            logging_obj=logging_obj,\n        )\n\n        if response.status_code != 200:\n            raise LangGraphError(status_code=response.status_code, message=str(response.read()))\n\n        # Create iterator for SSE stream\n        completion_stream: Final = self.get_streaming_response(model=model, raw_response=response)\n\n        streaming_response: Final = CustomStreamWrapper(\n            completion_stream=completion_stream,\n            model=model,\n            custom_llm_provider=custom_llm_provider,\n            logging_obj=logging_obj,\n        )\n\n        # LOGGING\n        logging_obj.post_call(\n            input=messages,\n            api_key=\"\",\n            original_response=\"first stream response received\",\n            additional_args={\"complete_input_dict\": data},\n        )","sourceCodeStart":294,"sourceCodeEnd":330,"githubUrl":"https://github.com/BerriAI/litellm/blob/6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d/litellm/llms/langgraph/chat/transformation.py#L294-L330","documentation":"For synchronous streaming requests to the LangGraph /runs/stream endpoint, any non-200 status from the server is converted into LangGraphError carrying the upstream status code and the raw response body (response.read()) as the message. The message is literally the response bytes stringified — it exists to surface the server's error detail (e.g. 404 unknown assistant, 401 bad key, 422 validation) to the caller.","triggerScenarios":"Streaming (stream=True) against a LangGraph server when the assistant/graph name is wrong (404), the api_key is invalid (401/403), the payload fails validation (422), or the deployment is restarting (503).","commonSituations":"Model name not matching a deployed graph; expired or wrong-scoped LangGraph API key; schema mismatch after updating the graph's input schema; server temporarily unavailable during deploys.","solutions":["Read the error message body: it contains the LangGraph server's own error JSON explaining the failure","404: verify the graph/assistant name in model=\"langgraph/<name>\" against the deployment","401/403: check the LANGGRAPH_API_KEY / api_key value","422: align the input payload (messages/format) with the graph's current input schema","5xx: retry after the deployment is healthy"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"def langgraph_stream_ready(api_base: str, api_key: str) -> bool:\n    import requests\n    r = requests.post(\n        f\"{api_base.rstrip('/')}/runs/stream\",\n        headers={\"Authorization\": f\"Bearer {api_key}\", \"Content-Type\": \"application/json\"},\n        json={\"assistant_id\": \"agent\", \"input\": {\"messages\": []}, \"stream_mode\": \"messages\"},\n        timeout=10,\n    )\n    return r.status_code == 200","typeGuard":null,"tryCatchPattern":"from litellm.llms.langgraph.chat.transformation import LangGraphError\n\nfor attempt in range(3):\n    try:\n        stream = litellm.completion(model=\"langgraph/agent\", messages=msgs, stream=True)\n        for chunk in stream:\n            ...\n        break\n    except LangGraphError as e:\n        if e.status_code in (401, 403, 404, 422):\n            raise  # config error — fix key/name/payload, do not retry\n        if e.status_code >= 500 and attempt < 2:\n            continue  # transient — retry\n        raise","preventionTips":["Parse e.status_code, not just the message body, to branch retry vs. fix","Keep graph/assistant names and input schemas in sync with the deployment via a config test","Wrap streaming calls in bounded retry for 5xx only; auth/validation errors are permanent"],"tags":["langgraph","streaming","http"],"backgroundTag":null,"analyzedSha":"6c2dcb801bf2b75c18f1bb24140e7cf57465cc4d","analyzedAt":"2026-08-15T07:12:03.035Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}