From 8eb015d2bcc7a71710fccd75029af70ac0ab2f5a Mon Sep 17 00:00:00 2001 From: Raju Ahmed Date: Sun, 28 Dec 2025 16:48:25 +0600 Subject: [PATCH 1/2] fix(context): added warning for multiple writes to response body warning works only in debug mode --- context.go | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/context.go b/context.go index e1d9be43..724695e3 100644 --- a/context.go +++ b/context.go @@ -1132,6 +1132,15 @@ func (c *Context) Render(code int, r render.Render) { return } + if c.Writer.Written() && IsDebugging() { + // Skip warning for SSE and streaming responses (status code -1) + if code != -1 { + if _, ok := r.(sse.Event); !ok { + debugPrint("[WARNING] Response body already written. Attempting to write again with status code %d", code) + } + } + } + if err := r.Render(c.Writer); err != nil { // Pushing error to c.Errors _ = c.Error(err) From dc128b72919a940ddbe2ad30687f7d2ad6cb9543 Mon Sep 17 00:00:00 2001 From: Raju Ahmed Date: Sun, 28 Dec 2025 17:52:39 +0600 Subject: [PATCH 2/2] test(context): add tests for multiple JSON and SSE writes in debug mode --- context_test.go | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/context_test.go b/context_test.go index 126646fc..af717a8b 100644 --- a/context_test.go +++ b/context_test.go @@ -1348,6 +1348,43 @@ func TestContextRenderNoContentData(t *testing.T) { assert.Equal(t, "text/csv", w.Header().Get("Content-Type")) } +// Test multiple JSON writes in debug mode +func TestContextRenderMultipleJSON(t *testing.T) { + w := httptest.NewRecorder() + c, _ := CreateTestContext(w) + + oldMode := os.Getenv("GIN_MODE") + defer os.Setenv("GIN_MODE", oldMode) + SetMode(DebugMode) + + output := captureOutput(t, func() { + c.JSON(http.StatusOK, H{"foo": "bar"}) + c.JSON(http.StatusOK, H{"baz": "qux"}) + }) + + assert.Equal(t, http.StatusOK, w.Code) + assert.Contains(t, output, "[WARNING] Response body already written") + assert.Contains(t, output, "status code 200") +} + +// Test multiple SSE writes in debug mode +func TestContextRenderMultipleSSE(t *testing.T) { + w := httptest.NewRecorder() + c, _ := CreateTestContext(w) + + oldMode := os.Getenv("GIN_MODE") + defer os.Setenv("GIN_MODE", oldMode) + SetMode(DebugMode) + + output := captureOutput(t, func() { + c.SSEvent("message", "test1") + c.SSEvent("message", "test2") + }) + + assert.Equal(t, http.StatusOK, w.Code) + assert.NotContains(t, output, "[WARNING] Response body already written") +} + func TestContextRenderSSE(t *testing.T) { w := httptest.NewRecorder() c, _ := CreateTestContext(w)