{"record":{"id":"1c002dda5513092d","repo":"HKUDS/DeepTutor","slug":"openai-api-error-error-text","errorCode":null,"errorMessage":"OpenAI API error: {error_text}","messagePattern":"OpenAI API error: (.+?)","errorType":"http","errorClass":"LLMAPIError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/llm/cloud_provider.py","lineNumber":426,"sourceCode":"                                    if isinstance(first_choice, Mapping):\n                                        message = cast(Mapping[str, object], first_choice).get(\n                                            \"message\"\n                                        )\n                                    else:\n                                        message = None\n                                    if isinstance(message, Mapping):\n                                        content = extract_response_content(\n                                            cast(dict[str, object], message)\n                                        )\n                            else:\n                                retry_text = await retry_resp.text()\n                                raise LLMAPIError(\n                                    f\"OpenAI API error: {retry_text}\",\n                                    status_code=retry_resp.status,\n                                    provider=binding or \"openai\",\n                                )\n                    else:\n                        raise LLMAPIError(\n                            f\"OpenAI API error: {error_text}\",\n                            status_code=resp.status,\n                            provider=binding or \"openai\",\n                        )\n        except aiohttp.ClientError as e:\n            # Handle connection errors with more specific messages\n            if \"forcibly closed\" in str(e).lower() or \"10054\" in str(e):\n                raise LLMAPIError(\n                    f\"Connection to {binding} API was forcibly closed. \"\n                    \"This may indicate network issues or server-side problems. \"\n                    \"Please check your internet connection and try again.\",\n                    status_code=0,\n                    provider=binding or \"openai\",\n                ) from e\n            else:\n                raise LLMAPIError(\n                    f\"Network error connecting to {binding} API: {e}\",\n                    status_code=0,","sourceCodeStart":408,"sourceCodeEnd":444,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/llm/cloud_provider.py#L408-L444","documentation":"Raised inside _openai_complete when the OpenAI-compatible endpoint returns a non-2xx status after the retry/retry-after handling branch did not apply. The raw response body (error_text) is embedded in the LLMAPIError along with status_code and provider, so the message mirrors whatever the server returned (e.g. 401 invalid key, 400 bad request, 429 exhausted).","triggerScenarios":"POSTing to an OpenAI-compatible chat completions endpoint that replies 400 (malformed payload/unsupported param), 401/403 (bad key), 404 (wrong base_url path), or 500; using a proxy or local server (vLLM, LM Studio, Ollama's OpenAI shim) that returns an error body.","commonSituations":"Misconfigured base_url pointing at the wrong path; provider rejects response_format or a tool param; model name not available on the endpoint; expired or revoked API key; reverse proxy returning HTML error pages.","solutions":["Read status_code and error_text from the LLMAPIError to see the server's own message.","Fix the underlying cause: correct base_url, valid model name for that endpoint, valid API key.","If the error mentions response_format, remove it or rely on the runtime disable_response_format_at_runtime retry.","For 429/5xx, add backoff retries at the caller or use KeyPool rotation."],"exampleFix":"// before\nresp = await complete(prompt=p, model=m, base_url=\"http://localhost:8000\")\n\n# after\ntry:\n    resp = await complete(prompt=p, model=m, base_url=\"http://localhost:8000/v1\")\nexcept LLMAPIError as e:\n    if e.status_code == 404:\n        raise RuntimeError(f\"Bad base_url or model: {e}\") from e\n    raise","handlingStrategy":"try-catch","validationCode":"# Not fully avoidable: server-side decision. Pre-check what you control:\nassert (model or \"\").strip(), \"model required\"\nassert base_url is None or base_url.startswith(\"http\"), \"base_url malformed\"","typeGuard":null,"tryCatchPattern":"try:\n    out = await complete(prompt=p, model=m, api_key=k, base_url=u)\nexcept LLMAPIError as e:\n    if e.status_code == 401:\n        refresh_key()\n    elif e.status_code == 429:\n        await asyncio.sleep(30)\n    else:\n        log.error(\"provider %s status %s: %s\", e.provider, e.status_code, e)\n        raise","preventionTips":["Always inspect status_code on LLMAPIError before deciding to retry.","Validate model names against the endpoint's model list at startup.","Keep base_url pointing at the documented API path."],"tags":["llm","openai","http-error","api-error"],"backgroundTag":"llm-api-http-error","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}