{"id":"59621e3234433801","repo":"labstack/echo","slug":"response-writer-flushing-is-not-supported-59621e","errorCode":null,"errorMessage":"response writer flushing is not supported","messagePattern":"response writer flushing is not supported","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"response.go","lineNumber":163,"sourceCode":"\tw.committed = true\n\tw.ResponseWriter.WriteHeader(statusCode)\n}\n\nfunc (w *delayedStatusWriter) Write(data []byte) (int, error) {\n\tif !w.committed {\n\t\tw.committed = true\n\t\tif w.status == 0 {\n\t\t\tw.status = http.StatusOK\n\t\t}\n\t\tw.ResponseWriter.WriteHeader(w.status)\n\t}\n\treturn w.ResponseWriter.Write(data)\n}\n\nfunc (w *delayedStatusWriter) Flush() {\n\terr := http.NewResponseController(w.ResponseWriter).Flush()\n\tif err != nil && errors.Is(err, http.ErrNotSupported) {\n\t\tpanic(errors.New(\"response writer flushing is not supported\"))\n\t}\n}\n\nfunc (w *delayedStatusWriter) Hijack() (net.Conn, *bufio.ReadWriter, error) {\n\treturn http.NewResponseController(w.ResponseWriter).Hijack()\n}\n\nfunc (w *delayedStatusWriter) Unwrap() http.ResponseWriter {\n\treturn w.ResponseWriter\n}\n\n// headResponseWriter captures the response that a GET handler would produce for a\n// rewritten HEAD request, suppresses the body, and preserves response metadata.\n//\n// The writer buffers status until the downstream handler returns, so it\n// can compute a Content-Length value from the number of body bytes that would have\n// been written by the GET handler. If the handler already sets Content-Length\n// explicitly, that value is preserved.","sourceCodeStart":145,"sourceCodeEnd":181,"githubUrl":"https://github.com/labstack/echo/blob/05489dc1730161df26b72d1ae2a3ba6fb8178fc7/response.go#L145-L181","documentation":"Panicked at request time by delayedStatusWriter.Flush (used in the error-handler path) when the underlying http.ResponseWriter does not support the http.Flusher interface (detected via http.NewResponseController returning http.ErrNotSupported). Flushing is needed when middleware or handlers call c.Response().Flush() while the delayed writer is buffering the status code; if the real writer cannot flush, there is no safe fallback, so Echo panics.","triggerScenarios":"An error occurs in the handler chain (delayedStatusWriter is engaged) and then something calls Flush on a writer whose chain does not implement http.Flusher — e.g., httptest.ResponseRecorder (which does implement Flush in newer Go, but custom recorders may not) or a bespoke in-memory writer.","commonSituations":"Tests using a custom ResponseWriter that omits Flush; or a deployment behind a non-standard server adapter whose writer lacks Flusher support, combined with the error-handling path that engages the delayed writer.","solutions":["Ensure the underlying http.ResponseWriter (or any wrapper in its Unwrap chain) implements http.Flusher (Flush()).","In tests, prefer httptest.NewRecorder() which supports Flusher, or wrap your custom writer to forward Flush to a real implementation.","Avoid calling c.Response().Flush() from middleware that may run inside the error-handling path unless you know the writer supports it.","If using a custom server adapter, document/verify that its ResponseWriter implements http.Flusher."],"exampleFix":"// before: custom writer has no Flush\ntype memWriter struct{ header http.Header; body bytes.Buffer }\n// after: implement http.Flusher\ntype memWriter struct{ header http.Header; body bytes.Buffer }\nfunc (w *memWriter) Flush() {} // satisfy http.Flusher\nfunc (w *memWriter) Unwrap() http.ResponseWriter { return nil }","handlingStrategy":"validation","validationCode":"func supportsFlush(rw http.ResponseWriter) bool {\n    // walk the Unwrap chain the same way ResponseController does\n    for {\n        if _, ok := rw.(http.Flusher); ok { return true }\n        if u, ok := rw.(interface{ Unwrap() http.ResponseWriter }); ok {\n            rw = u.Unwrap()\n            continue\n        }\n        return false\n    }\n}","typeGuard":null,"tryCatchPattern":"// recover at the server boundary if a non-flushable writer is unavoidable\ndefer func() {\n    if r := recover(); r != nil {\n        c.Error(echo.NewHTTPError(http.StatusInternalServerError, fmt.Sprintf(\"%v\", r)))\n    }\n}()","preventionTips":["Make sure the underlying http.ResponseWriter (or a wrapper in its Unwrap chain) implements http.Flusher.","In tests, use httptest.NewRecorder() (supports Flush) or implement Flush() on custom writers.","Avoid calling c.Response().Flush() from middleware that may run inside the error-handling path on non-flushable writers.","Verify any custom server adapter's ResponseWriter implements http.Flusher before deploying."],"tags":["echo","response","flusher","panic","runtime","error-handler"],"analyzedSha":"05489dc1730161df26b72d1ae2a3ba6fb8178fc7","analyzedAt":"2026-08-04T21:32:47.783Z","schemaVersion":2}