fix: Add graceful error handling for ChunkedEncodingError during streaming (#57)

Fixes connection interruptions from ChatGPT API by catching ChunkedEncodingError
and gracefully ending the stream with [DONE] instead of returning 500 errors.

Two-level error handling:
1. Catches errors during stream initialization
2. Catches errors during stream iteration

This prevents abrupt failures when the upstream connection is interrupted mid-response.
This commit is contained in:
Alexx
2025-10-20 18:38:47 +01:00
committed by GitHub
parent b4d062ff3f
commit fd900eb7af

View File

@@ -432,23 +432,46 @@ def sse_translate_chat(
except Exception: except Exception:
return None return None
try: try:
for raw in upstream.iter_lines(decode_unicode=False): try:
line_iterator = upstream.iter_lines(decode_unicode=False)
except requests.exceptions.ChunkedEncodingError as e:
if verbose and vlog:
vlog(f"Failed to start stream: {e}")
yield b"data: [DONE]\n\n"
return
for raw in line_iterator:
try:
if not raw: if not raw:
continue continue
line = raw.decode("utf-8", errors="ignore") if isinstance(raw, (bytes, bytearray)) else raw line = (
raw.decode("utf-8", errors="ignore")
if isinstance(raw, (bytes, bytearray))
else raw
)
if verbose and vlog: if verbose and vlog:
vlog(line) vlog(line)
if not line.startswith("data: "): if not line.startswith("data: "):
continue continue
data = line[len("data: "):].strip() data = line[len("data: ") :].strip()
if not data: if not data:
continue continue
if data == "[DONE]": if data == "[DONE]":
break break
try: try:
evt = json.loads(data) evt = json.loads(data)
except Exception: except (json.JSONDecodeError, UnicodeDecodeError):
continue continue
except (
requests.exceptions.ChunkedEncodingError,
ConnectionError,
BrokenPipeError,
) as e:
# Connection interrupted mid-stream - end gracefully
if verbose and vlog:
vlog(f"Stream interrupted: {e}")
yield b"data: [DONE]\n\n"
return
kind = evt.get("type") kind = evt.get("type")
if isinstance(evt.get("response"), dict) and isinstance(evt["response"].get("id"), str): if isinstance(evt.get("response"), dict) and isinstance(evt["response"].get("id"), str):
response_id = evt["response"].get("id") or response_id response_id = evt["response"].get("id") or response_id