flipped-aurora/gin-vue-admin · error
读取上游流式响应失败: %w
Error message
读取上游流式响应失败: %w
What it means
After writing each chunk, proxyLLMStream checks the Read error from the upstream body. If it is not io.EOF (i.e. the stream ended abnormally rather than cleanly), it returns fmt.Errorf("读取上游流式响应失败: %w", readErr) — 'failed to read upstream streaming response' — wrapping the underlying read error so the client-facing caller of LLMAuto knows the upstream stream broke before completion.
Source
Thrown at server/api/v1/system/sys_auto_code.go:209
c.Writer.Header().Set("Connection", "keep-alive")
c.Writer.Header().Set("X-Accel-Buffering", "no")
c.Status(res.StatusCode)
flusher.Flush()
buf := make([]byte, 32*1024)
for {
n, readErr := res.Body.Read(buf)
if n > 0 {
if _, writeErr := c.Writer.Write(buf[:n]); writeErr != nil {
return fmt.Errorf("向客户端写入流式响应失败: %w", writeErr)
}
flusher.Flush()
}
if readErr != nil {
if errors.Is(readErr, io.EOF) {
return nil
}
return fmt.Errorf("读取上游流式响应失败: %w", readErr)
}
}
}
func copyLLMStreamHeaders(dst, src http.Header) {
for _, key := range []string{
"Content-Type",
"Cache-Control",
"Content-Encoding",
"Content-Language",
"X-Accel-Buffering",
} {
if value := src.Get(key); value != "" {
dst.Set(key, value)
}
}
}
View on GitHub (pinned to 3136500ef3)
Solutions
- Inspect the wrapped error: 'connection reset by peer'/'unexpected EOF' indicates upstream/network breakage; 'context deadline exceeded' indicates a timeout.
- Increase the outbound HTTP client's timeout / configure its Transport (idle conn, response header timeout) for long streams.
- Retry the generation once on transient read failures; make the client resume or regenerate gracefully on truncated answers.
- Check provider status pages/logs — repeated mid-stream resets often come from the LLM service itself or an intermediary proxy.
Example fix
// before
client := &http.Client{} // default timeouts too tight for long streams
// after
client := &http.Client{
Timeout: 0, // stream-managed
Transport: &http.Transport{ResponseHeaderTimeout: 60 * time.Second, IdleConnTimeout: 90 * time.Second},
} Defensive patterns
Strategy: retry
Try / catch
err := api.proxyLLMStream(c, payload)
if err != nil {
if strings.Contains(err.Error(), "读取上游流式响应失败") {
// truncated stream: notify client to regenerate
c.SSEvent("error", "upstream stream interrupted")
return nil
}
return err
} Prevention
- Configure the outbound http.Client Transport for long-lived streams (no overall timeout)
- Retry generation once on transient mid-stream read errors
- Alert on recurring 'unexpected EOF' patterns — usually provider-side
- Keep partial output on truncation so users lose nothing already generated
When it happens
Trigger: Mid-stream, res.Body.Read returns a non-EOF error: upstream LLM connection reset, provider timeout, TLS interruption, proxy between server and provider cutting the chunked response, or the provider aborting an over-long generation.
Common situations: Very long completions exceed provider/proxy stream limits; unstable network to the LLM endpoint; upstream rate-limit kills active streams; keep-alive idle timeouts on the outbound HTTP transport.
Related errors
- 上游大模型流式服务返回非 2xx: status=%d content-type=%s read-body-err=%w
- LLM stream request timed out
- 上游大模型流式服务返回非 2xx: status=%d content-type=%s body=%s
- 向客户端写入流式响应失败: %w
- 调用上游大模型失败: %w
AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31).
Data as JSON: /api/errors/7a8243b98e04e8ee.
Report an issue: GitHub.