{"record":{"id":"d8143fe584cfd88f","repo":"HKUDS/DeepTutor","slug":"connection-to-binding-api-was-forcibly-closed-t","errorCode":null,"errorMessage":"Connection to {binding} API was forcibly closed. This may indicate network issues or server-side problems. Please check your internet connection and try again.","messagePattern":"Connection to (.+?) API was forcibly closed\\. This may indicate network issues or server-side problems\\. Please check your internet connection and try again\\.","errorType":"http","errorClass":"LLMAPIError","httpStatus":null,"severity":"error","filePath":"deeptutor/services/llm/cloud_provider.py","lineNumber":434,"sourceCode":"                                            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,\n                    provider=binding or \"openai\",\n                ) from e\n\n    if content is not None:\n        # Clean thinking tags from response using unified utility\n        return clean_thinking_tags(content, binding, model)\n\n    raise LLMConfigError(\"Cloud completion failed: no valid configuration\")","sourceCodeStart":416,"sourceCodeEnd":452,"githubUrl":"https://github.com/HKUDS/DeepTutor/blob/3e82f130422a813cdd73c10b21a44e9325f5821a/deeptutor/services/llm/cloud_provider.py#L416-L452","documentation":"Caught as an aiohttp.ClientError whose string contains 'forcibly closed' or Winsock error 10054 — the TCP connection was reset mid-request. _openai_complete maps it to LLMAPIError with status_code=0 and a user-friendly remediation message, chaining the original exception. It is a transport-level failure, not an API-level one.","triggerScenarios":"Remote server or an intermediate firewall/NAT/proxy drops the TCP connection during a long completion; flaky Wi-Fi or VPN dropout; Windows environments where 10054 surfaces in the exception text; cloud LLM endpoints closing idle long-running requests.","commonSituations":"Corporate proxies killing long-lived POSTs; mobile/tethered networks; long streaming completions on unstable links; regional network blocking of the provider endpoint.","solutions":["Retry the request with exponential backoff (status_code=0 marks it transient).","Check network path: disable VPN/proxy temporarily, test curl to the same base_url.","Reduce request duration (smaller max_tokens, enable streaming) so the connection is short-lived.","If persistent, point base_url at a reachable mirror or deploy closer egress."],"exampleFix":"// before\nout = await complete(prompt=p, model=m)\n\n# after\nfor attempt in range(3):\n    try:\n        out = await complete(prompt=p, model=m)\n        break\n    except LLMAPIError as e:\n        if e.status_code != 0 or attempt == 2:\n            raise\n        await asyncio.sleep(2 ** attempt)","handlingStrategy":"retry","validationCode":"# Cannot validate a remote reset in advance; keep requests short instead:\nkwargs[\"max_tokens\"] = min(int(kwargs.get(\"max_tokens\", 1024)), 1024)","typeGuard":null,"tryCatchPattern":"for attempt in range(3):\n    try:\n        out = await complete(prompt=p, model=m)\n        break\n    except LLMAPIError as e:\n        if e.status_code != 0 or attempt == 2:\n            raise\n        await asyncio.sleep(2 ** attempt)","preventionTips":["Treat status_code==0 as transient and retry with backoff.","Prefer streaming for long generations to keep each connection short.","Monitor network health (VPN/proxy) when long completions fail repeatedly."],"tags":["llm","network","connection-reset","aiohttp","transient"],"backgroundTag":"connection-reset","analyzedSha":"3e82f130422a813cdd73c10b21a44e9325f5821a","analyzedAt":"2026-08-27T06:57:25.364Z","schemaVersion":2},"datasetVersion":"2026-08-27T08:17:20.692Z"}