gofr-dev/gofr · error
%w: cannot hijack connection
Error message
%w: cannot hijack connection
What it means
This wrapped error is produced by StatusResponseWriter.Hijack in GoFr's logging middleware: when the inner http.ResponseWriter cannot be cast to http.Hijacker, it returns fmt.Errorf("%w: cannot hijack connection", errHijackNotSupported). Callers can match it with errors.Is against the sentinel. It means the connection upgrade requested by the handler cannot proceed through this writer.
Source
Thrown at pkg/gofr/http/middleware/logger.go:90
}
return w.status
}
// Unwrap returns the wrapped ResponseWriter so http.NewResponseController can reach the underlying
// connection for Flush and SetWriteDeadline — needed for streaming responses.
func (w *StatusResponseWriter) Unwrap() http.ResponseWriter {
return w.ResponseWriter
}
// Hijack implements the http.Hijacker interface. So that we are able to upgrade to a websocket
// connection that requires the responseWriter implementation to implement this method.
func (w *StatusResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {
if hijacker, ok := w.ResponseWriter.(http.Hijacker); ok {
return hijacker.Hijack()
}
return nil, nil, fmt.Errorf("%w: cannot hijack connection", errHijackNotSupported)
}
// RequestLog represents a log entry for HTTP requests.
type RequestLog struct {
TraceID string `json:"trace_id,omitempty"`
SpanID string `json:"span_id,omitempty"`
StartTime string `json:"start_time,omitempty"`
ResponseTime int64 `json:"response_time,omitempty"`
Method string `json:"method,omitempty"`
UserAgent string `json:"user_agent,omitempty"`
IP string `json:"ip,omitempty"`
URI string `json:"uri,omitempty"`
Response int `json:"response,omitempty"`
}
// zeroTraceID is the canonical 32-zero string the W3C trace-context
// invalid TraceID prints to. We use it for the X-Correlation-ID
// response header AND for the request-log field when no SpanContextView on GitHub (pinned to 187eb24962)
Solutions
- Make every wrapper in the writer chain implement http.Hijacker by delegating to the inner writer
- Exclude upgrade-style routes from wrapping by non-hijackable middleware
- Handle the error in the handler (close/flush normally or return 500) using errors.Is
- Test upgrades with a full httptest.Server, which provides a hijackable connection
Example fix
// before
conn, rw, err := w.Hijack() // "response writer does not support hijacking: cannot hijack connection"
// after
conn, rw, err := w.Hijack()
if err != nil {
if errors.Is(err, middleware.ErrHijackNotSupported) {
http.Error(w, "upgrade not supported", http.StatusInternalServerError)
return
}
} Defensive patterns
Strategy: type-guard
Validate before calling
if h, ok := w.(http.Hijacker); !ok {
return fmt.Errorf("writer %T cannot hijack; needed for connection upgrade", w)
} else { _ = h } Type guard
func hijacker(w http.ResponseWriter) (http.Hijacker, bool) {
h, ok := w.(http.Hijacker)
return h, ok
} Try / catch
conn, rw, err := srw.Hijack()
if errors.Is(err, middleware.ErrHijackNotSupported) {
log.Warn("connection upgrade not possible through this writer chain")
http.Error(srw, "upgrade unsupported", http.StatusInternalServerError)
return
} Prevention
- Forward the Hijacker interface through all custom middleware writers
- Route upgrade-only handlers outside wrapping middleware or unwrap before hijacking
- Test upgrades end-to-end with httptest.NewServer
- Check errors.Is(err, ErrHijackNotSupported) to give clear upgrade-failure responses
When it happens
Trigger: A handler (typically a WebSocket/upgrade request) calls Hijack on the logging middleware's StatusResponseWriter while the response writer beneath it does not implement http.Hijacker.
Common situations: WebSocket endpoints routed through logging-only writer chains, third-party middleware that wraps the writer without forwarding Hijack, or test doubles lacking Hijack support.
Related errors
- response writer does not support hijacking
- Could not open WebSocket connection
- errFileNotOpenForReading
- response retrieved is nil
- s3 backend did not honor the requested byte range
AI-assisted analysis of gofr-dev/gofr@187eb24962 (2026-09-01).
Data as JSON: /api/errors/8c6d08caa596eb11.
Report an issue: GitHub.