Skip to content

fix: flush status immediately for no-body response codes#4714

Closed
xbrxr03 wants to merge 1 commit into
gin-gonic:masterfrom
xbrxr03:fix/status-flush-no-body
Closed

fix: flush status immediately for no-body response codes#4714
xbrxr03 wants to merge 1 commit into
gin-gonic:masterfrom
xbrxr03:fix/status-flush-no-body

Conversation

@xbrxr03

@xbrxr03 xbrxr03 commented Jun 22, 2026

Copy link
Copy Markdown

Problem

ctx.Status(code) doesn't flush the status code to the underlying http.ResponseWriter when no body is written. This causes httptest.ResponseRecorder and similar wrappers to see the default 200 instead of the actual status code.

recorder := httptest.NewRecorder()
c, _ := gin.CreateTestContext(recorder)
c.Status(http.StatusNoContent)
fmt.Println(recorder.Code) // 200 — should be 204

Reported in #4071.

Root Cause

ctx.Status() calls c.Writer.WriteHeader(code), which only stores the status in gin's responseWriter buffer. The status gets flushed to the underlying writer when Write() is called (which triggers WriteHeaderNow()). But for status codes that never have a body (1xx, 204, 304), no Write() ever happens, so the status never reaches the underlying ResponseRecorder.

This is inconsistent with ctx.Render(), which already calls WriteHeaderNow() for no-body status codes.

Fix

When Status() is called with a no-body status code (where bodyAllowedForStatus() returns false), immediately flush the status to the underlying writer via WriteHeaderNow(). This mirrors the existing behavior in Render() and matches user expectations.

For status codes that allow a body (e.g. 200), Status() continues to buffer the status until Write() is called, preserving the existing behavior for handlers that set a status before writing content.

Tests

  • TestContextStatusFlushesNoBodyCodes: verifies 100, 101, 102, 204, and 304 flush immediately
  • TestContextStatusWithBodyDoesNotFlushEarly: verifies 200 still buffers until Write() is called

All existing tests continue to pass.

Fixes #4071

ctx.Status() sets the status on gin's responseWriter but never flushes
it to the underlying http.ResponseWriter when no body is written. This
causes httptest.ResponseRecorder and similar wrappers to see the default
200 instead of the actual status code.

This particularly affects status codes that never have a body (1xx, 204,
304) where handlers typically call ctx.Status() without writing content.

The fix mirrors the existing behavior in ctx.Render(), which already
calls WriteHeaderNow() for no-body status codes. By flushing immediately
for these codes in Status(), the correct status propagates to the
underlying writer without requiring a separate Write() call.

Fixes gin-gonic#4071
@codecov

codecov Bot commented Jun 22, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 98.39%. Comparing base (3dc1cd6) to head (065f526).
⚠️ Report is 286 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #4714      +/-   ##
==========================================
- Coverage   99.21%   98.39%   -0.83%     
==========================================
  Files          42       48       +6     
  Lines        3182     3172      -10     
==========================================
- Hits         3157     3121      -36     
- Misses         17       42      +25     
- Partials        8        9       +1     
Flag Coverage Δ
?
--ldflags="-checklinkname=0" -tags sonic 98.37% <100.00%> (?)
-tags go_json 98.31% <100.00%> (?)
-tags nomsgpack 98.36% <100.00%> (?)
go-1.18 ?
go-1.19 ?
go-1.20 ?
go-1.21 ?
go-1.25 98.39% <100.00%> (?)
go-1.26 98.39% <100.00%> (?)
macos-latest 98.39% <100.00%> (-0.83%) ⬇️
ubuntu-latest 98.39% <100.00%> (-0.83%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@xbrxr03

xbrxr03 commented Jun 29, 2026

Copy link
Copy Markdown
Author

Closing this PR due to lack of maintainer engagement. I'm happy to reopen if there's interest. Thanks for the great project.

@xbrxr03 xbrxr03 closed this Jun 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ctx.Status() does not affect httptest.ResponseRecorder while ctx.JSON() does

2 participants