{"record":{"id":"fe23dfc2d4c0d434","repo":"flipped-aurora/gin-vue-admin","slug":"sse-w","errorCode":null,"errorMessage":"写入 SSE 事件失败: %w","messagePattern":"写入 SSE 事件失败: %w","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"server/api/v1/system/sys_auto_code_sse.go","lineNumber":208,"sourceCode":"\t\t\tData:  gin.H{\"done\": true},\n\t\t})\n\t}\n\n\tvar payload interface{}\n\tif err := json.Unmarshal([]byte(rawData), &payload); err != nil {\n\t\tpayload = rawData\n\t}\n\n\treturn renderSSE(c, sse.Event{\n\t\tId:    eventID,\n\t\tEvent: eventName,\n\t\tData:  payload,\n\t})\n}\n\nfunc renderSSE(c *gin.Context, event sse.Event) error {\n\tif err := event.Render(c.Writer); err != nil {\n\t\treturn fmt.Errorf(\"写入 SSE 事件失败: %w\", err)\n\t}\n\tif flusher, ok := c.Writer.(http.Flusher); ok {\n\t\tflusher.Flush()\n\t}\n\treturn nil\n}\n","sourceCodeStart":190,"sourceCodeEnd":215,"githubUrl":"https://github.com/flipped-aurora/gin-vue-admin/blob/3136500ef380842b0eb6c4daa87c3f8a47fcf9e0/server/api/v1/system/sys_auto_code_sse.go#L190-L215","documentation":"renderSSE writes an sse.Event to the gin response writer and flushes. This error wraps a failure of event.Render (client disconnected, broken pipe) so the caller can stop streaming instead of continuing to write to a dead connection.","triggerScenarios":"A client that requested the SSE stream disconnects (closes the browser tab, cancels fetch/EventSource, network drop) while renderSSE attempts to write/flush an event.","commonSituations":"User cancels a code-generation stream mid-way; client navigates away; mobile client loses connectivity; reverse proxy closes client connection.","solutions":["Treat this as a normal client-disconnect: stop streaming and clean up, do not retry the write","Log at debug/info level rather than error when the wrapped error indicates broken pipe/connection canceled","Use c.Request.Context() cancellation to abort the upstream request when the client goes away","Verify the response headers are written before the first event (status 200, text/event-stream) to avoid header-write errors"],"exampleFix":"// before\nif err := renderSSE(c, ev); err != nil {\n    logger.Error(...)\n}\n// after\nif err := renderSSE(c, ev); err != nil {\n    if errors.Is(err, syscall.EPIPE) || c.Request.Context().Err() != nil {\n        return nil // client disconnected; stop quietly\n    }\n    return err\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"if err := renderSSE(c, ev); err != nil {\n    if c.Request.Context().Err() != nil || errors.Is(err, syscall.EPIPE) {\n        return nil // client gone, stop silently\n    }\n    return err\n}","preventionTips":["Always check c.Request.Context().Err() before writing each event","Stop the upstream request when the client disconnects (context propagation)","Log disconnects at debug level to avoid alert noise"],"tags":["sse","gin","client-disconnect"],"backgroundTag":"broken-pipe-client-disconnect","analyzedSha":"3136500ef380842b0eb6c4daa87c3f8a47fcf9e0","analyzedAt":"2026-08-31T13:50:02.721Z","schemaVersion":2},"datasetVersion":"2026-08-31T19:17:28.585Z"}