flipped-aurora/gin-vue-admin · error
当前响应不支持流式输出
Error message
当前响应不支持流式输出
What it means
proxyLLMStream relays the upstream LLM SSE stream to the gin response. gin's ResponseWriter only supports Flush() when it implements http.Flusher; on some writers (e.g. wrapped/hijacked writers, or when a middleware replaced the writer) the assertion fails and the proxy aborts with this error.
Source
Thrown at server/api/v1/system/sys_auto_code.go:181
func (autoApi *AutoCodeApi) proxyLLMStream(c *gin.Context, llm common.JSONMap) error {
res, err := autoCodeService.LLMAutoStream(c.Request.Context(), llm)
if err != nil {
return err
}
defer res.Body.Close()
if res.StatusCode < 200 || res.StatusCode >= 300 {
body, readErr := io.ReadAll(res.Body)
if readErr != nil {
return fmt.Errorf("上游大模型流式服务返回非 2xx: status=%d content-type=%s read-body-err=%w", res.StatusCode, res.Header.Get("Content-Type"), readErr)
}
return fmt.Errorf("上游大模型流式服务返回非 2xx: status=%d content-type=%s body=%s", res.StatusCode, res.Header.Get("Content-Type"), previewResponseBody(body))
}
flusher, ok := c.Writer.(http.Flusher)
if !ok {
return errors.New("当前响应不支持流式输出")
}
copyLLMStreamHeaders(c.Writer.Header(), res.Header)
if c.Writer.Header().Get("Content-Type") == "" {
c.Writer.Header().Set("Content-Type", "text/event-stream; charset=utf-8")
}
if c.Writer.Header().Get("Cache-Control") == "" {
c.Writer.Header().Set("Cache-Control", "no-cache")
}
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 {View on GitHub (pinned to 3136500ef3)
Solutions
- Audit middleware for custom ResponseWriter wrappers and ensure they embed http.Flusher and forward Flush()
- Remove/reorder middleware that replaces c.Writer on the LLM stream route
- Test with the vanilla gin engine route to confirm the writer supports flushing
Example fix
// before
type wrappedWriter struct { gin.ResponseWriter }
// after
type wrappedWriter struct {
gin.ResponseWriter // already implements Flusher; do not shadow Flush
} Defensive patterns
Strategy: validation
Validate before calling
flusher, ok := c.Writer.(http.Flusher)
if !ok {
// fail fast with a clear middleware hint
return fmt.Errorf("当前响应不支持流式输出: middleware %T replaced the writer", c.Writer)
} Try / catch
if err := proxyLLMStream(c, upstream); err != nil {
if strings.Contains(err.Error(), "不支持流式输出") {
logger.Error("ResponseWriter cannot flush; check middleware wrapping c.Writer")
}
respondSSEError(c, err)
} Prevention
- Keep custom gin ResponseWriter wrappers embedding gin.ResponseWriter
- Review middleware ordering on SSE routes after every dependency upgrade
- Add a unit test asserting c.Writer implements http.Flusher on SSE routes
When it happens
Trigger: c.Writer.(http.Flusher) type assertion fails while proxying a successful (2xx) upstream LLM stream response.
Common situations: A middleware wraps the gin Context.Writer with a custom ResponseWriter that doesn't embed http.Flusher; running behind a setup that hijacks or wraps the connection; unusual test harness writers.
Related errors
AI-assisted analysis of flipped-aurora/gin-vue-admin@3136500ef3 (2026-08-31).
Data as JSON: /api/errors/b7e7a70cd597966d.
Report an issue: GitHub.