gin-gonic/gin · error · errHijackAlreadyWritten
gin: response body already written
Error message
gin: response body already written
What it means
errHijackAlreadyWritten is returned by ResponseWriter.Hijack (response_writer.go:115) when Hijack is called after response body bytes (size > 0) have already been written. Once body data is on the wire the connection can no longer be upgraded/hijacked cleanly; Gin permits hijack only before body writes (size == -1) or right after headers (size == 0).
Source
Thrown at response_writer.go:20
// Use of this source code is governed by a MIT style
// license that can be found in the LICENSE file.
package gin
import (
"bufio"
"errors"
"io"
"net"
"net/http"
)
const (
noWritten = -1
defaultStatus = http.StatusOK
)
var errHijackAlreadyWritten = errors.New("gin: response body already written")
// ResponseWriter ...
type ResponseWriter interface {
http.ResponseWriter
http.Hijacker
http.Flusher
http.CloseNotifier
// Status returns the HTTP response status code of the current request.
Status() int
// Size returns the number of bytes already written into the response http body.
// See Written()
Size() int
// WriteString writes the string into the response body.
WriteString(string) (int, error)
View on GitHub (pinned to 34dac209ff)
Solutions
- Ensure no body bytes are written before calling Hijack; branch the handler so the upgrade path never writes a normal response.
- Move the WebSocket upgrade to the very first thing the handler does, before any c.JSON / c.String.
- If you conditionally write, call c.Writer.Written() / c.Writer.Size() and skip writing before attempting Hijack.
Example fix
// before
c.String(http.StatusOK, "hi")
conn, _, _ := c.Writer.Hijack() // error
// after
conn, buf, err := c.Writer.Hijack()
if err != nil { /* handle */ return }
defer conn.Close()
// do websocket handshake on conn Defensive patterns
Strategy: validation
Validate before calling
if c.Writer.Written() || c.Writer.Size() > 0 {
return errors.New("cannot hijack after body written")
}
conn, buf, err := c.Writer.Hijack() Try / catch
conn, buf, err := c.Writer.Hijack()
if err != nil {
if errors.Is(err, errHijackAlreadyWritten) {
// response already started; cannot upgrade
}
} Prevention
- Branch handlers: a websocket/upgrade path must not write any body before Hijack.
- Check c.Writer.Size() == 0 (or Written()==false) before upgrading.
- Keep websocket upgrades at the very start of the handler chain.
When it happens
Trigger: Calling c.Writer.Hijack() after a c.JSON / c.String / c.Write that wrote body bytes; WebSocket upgrade libraries (e.g. github.com/coder/websocket) attempting to upgrade after the handler wrote a partial response; SSE handlers that wrote an event then try to upgrade.
Common situations: Mixing a normal HTTP response with a WebSocket upgrade in the same handler; flushing headers + partial body then calling Hijack; middleware that writes an error before delegating to a websocket upgrader.
Related errors
- unknown type
- can not convert to map slices of strings
- can not convert to map of strings
- invalid request
- unsupported field type for multipart.FileHeader
AI-assisted analysis of gin-gonic/gin@34dac209ff (2026-08-04).
Data as JSON: /data/errors/3bb45247e1350c9a.json.
Report an issue: GitHub.