{"record":{"id":"8c6d08caa596eb11","repo":"gofr-dev/gofr","slug":"w-cannot-hijack-connection","errorCode":null,"errorMessage":"%w: cannot hijack connection","messagePattern":"%w: cannot hijack connection","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/gofr/http/middleware/logger.go","lineNumber":90,"sourceCode":"\t}\n\n\treturn w.status\n}\n\n// Unwrap returns the wrapped ResponseWriter so http.NewResponseController can reach the underlying\n// connection for Flush and SetWriteDeadline — needed for streaming responses.\nfunc (w *StatusResponseWriter) Unwrap() http.ResponseWriter {\n\treturn w.ResponseWriter\n}\n\n// Hijack implements the http.Hijacker interface. So that we are able to upgrade to a websocket\n// connection that requires the responseWriter implementation to implement this method.\nfunc (w *StatusResponseWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {\n\tif hijacker, ok := w.ResponseWriter.(http.Hijacker); ok {\n\t\treturn hijacker.Hijack()\n\t}\n\n\treturn nil, nil, fmt.Errorf(\"%w: cannot hijack connection\", errHijackNotSupported)\n}\n\n// RequestLog represents a log entry for HTTP requests.\ntype RequestLog struct {\n\tTraceID      string `json:\"trace_id,omitempty\"`\n\tSpanID       string `json:\"span_id,omitempty\"`\n\tStartTime    string `json:\"start_time,omitempty\"`\n\tResponseTime int64  `json:\"response_time,omitempty\"`\n\tMethod       string `json:\"method,omitempty\"`\n\tUserAgent    string `json:\"user_agent,omitempty\"`\n\tIP           string `json:\"ip,omitempty\"`\n\tURI          string `json:\"uri,omitempty\"`\n\tResponse     int    `json:\"response,omitempty\"`\n}\n\n// zeroTraceID is the canonical 32-zero string the W3C trace-context\n// invalid TraceID prints to. We use it for the X-Correlation-ID\n// response header AND for the request-log field when no SpanContext","sourceCodeStart":72,"sourceCodeEnd":108,"githubUrl":"https://github.com/gofr-dev/gofr/blob/187eb24962502e91f1fee856230670958b66e89c/pkg/gofr/http/middleware/logger.go#L72-L108","documentation":"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.","triggerScenarios":"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.","commonSituations":"WebSocket endpoints routed through logging-only writer chains, third-party middleware that wraps the writer without forwarding Hijack, or test doubles lacking Hijack support.","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"],"exampleFix":"// before\nconn, rw, err := w.Hijack() // \"response writer does not support hijacking: cannot hijack connection\"\n// after\nconn, rw, err := w.Hijack()\nif err != nil {\n    if errors.Is(err, middleware.ErrHijackNotSupported) {\n        http.Error(w, \"upgrade not supported\", http.StatusInternalServerError)\n        return\n    }\n}","handlingStrategy":"type-guard","validationCode":"if h, ok := w.(http.Hijacker); !ok {\n    return fmt.Errorf(\"writer %T cannot hijack; needed for connection upgrade\", w)\n} else { _ = h }","typeGuard":"func hijacker(w http.ResponseWriter) (http.Hijacker, bool) {\n    h, ok := w.(http.Hijacker)\n    return h, ok\n}","tryCatchPattern":"conn, rw, err := srw.Hijack()\nif errors.Is(err, middleware.ErrHijackNotSupported) {\n    log.Warn(\"connection upgrade not possible through this writer chain\")\n    http.Error(srw, \"upgrade unsupported\", http.StatusInternalServerError)\n    return\n}","preventionTips":["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"],"tags":["http","websocket","hijack","middleware","gofr"],"backgroundTag":"hijack-not-supported","analyzedSha":"187eb24962502e91f1fee856230670958b66e89c","analyzedAt":"2026-09-01T20:34:54.554Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T10:18:20.063Z"}