{"record":{"id":"b7c118c542955e4c","repo":"HKUDS/DeepTutor","slug":"anthropic-stream-error-error-text","errorCode":null,"errorMessage":"Anthropic stream error: {error_text}","messagePattern":"Anthropic stream error: (.+?)","errorType":"http","errorClass":"LLMAPIError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/llm/cloud_provider.py","lineNumber":785,"sourceCode":"    temperature_value = temperature if temperature is not None else 0.7\n    data: dict[str, object] = {\n        \"model\": model,\n        \"system\": system_content,\n        \"messages\": msg_list,\n        \"max_tokens\": max_tokens_value,\n        \"temperature\": temperature_value,\n        \"stream\": True,\n    }\n\n    timeout = aiohttp.ClientTimeout(total=300)\n    connector = _get_aiohttp_connector()\n    async with aiohttp.ClientSession(\n        timeout=timeout, connector=connector, trust_env=True\n    ) as session:\n        async with session.post(url, headers=headers, json=data) as response:\n            if response.status != 200:\n                error_text = await response.text()\n                raise LLMAPIError(\n                    f\"Anthropic stream error: {error_text}\",\n                    status_code=response.status,\n                    provider=\"anthropic\",\n                )\n\n            async for line in response.content:\n                line_str = line.decode(\"utf-8\").strip()\n                if not line_str or not line_str.startswith(\"data:\"):\n                    continue\n\n                data_str = line_str[5:].strip()\n                if not data_str:\n                    continue\n\n                try:\n                    chunk_data = cast(dict[str, object], json.loads(data_str))\n                    event_type = chunk_data.get(\"type\")\n                    if event_type == \"content_block_delta\":","sourceCodeStart":767,"sourceCodeEnd":803,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/llm/cloud_provider.py#L767-L803","documentation":"The initial status check of _anthropic_stream: the POST for the SSE stream returned non-200, so the body is read and wrapped in LLMAPIError with the status and provider before any lines are iterated. The embedded error_text is Anthropic's own error JSON, so the message pinpoints the server-side reason.","triggerScenarios":"Starting a Claude stream with an invalid key (401), unavailable model (404), rate limit (429), or overloaded service (529); proxy gateways rejecting stream:true.","commonSituations":"Rate-limited Claude accounts during bursts; model name typos; region-blocked endpoints routed via proxy; long-running apps holding stale keys past rotation.","solutions":["Decode e.status_code + error_text to find the exact cause (auth vs model vs limit).","429/529 → back off and retry, or rotate keys via KeyPool.","401 → refresh the API key in the profile.","404 → verify the model identifier exists for the account."],"exampleFix":"// before\nasync for chunk in stream(prompt=p, binding=\"anthropic\", model=\"claude-3\", api_key=k):\n    ...\n\n# after\nasync for chunk in stream(prompt=p, binding=\"anthropic\", model=\"claude-sonnet-4\", api_key=k):\n    ...","handlingStrategy":"retry","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    async for chunk in stream(prompt=p, binding=\"anthropic\", model=m, api_key=k):\n        ...\nexcept LLMAPIError as e:\n    if e.status_code in (429, 529):\n        await asyncio.sleep(30)  # then retry\n    elif e.status_code == 401:\n        raise RuntimeError(\"invalid Anthropic key\") from e\n    else:\n        raise","preventionTips":["Use KeyPool rotation plus backoff for bursty Claude workloads.","Verify model identifiers exist for your account before streaming.","Degrade gracefully to non-streaming when gateways reject SSE."],"tags":["llm","anthropic","streaming","http-error","rate-limit"],"backgroundTag":"llm-api-http-error","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}