labstack/echo · error

echo: response writer %T does not support flushing (http.Flu

Error message

echo: response writer %T does not support flushing (http.Flusher interface)

What it means

Panicked by Response.Flush() (response.go:85) when http.NewResponseController(r.ResponseWriter).Flush() returns an error that errors.Is http.ErrNotSupported. This means no writer in the wrapped ResponseWriter chain implements http.Flusher, so buffered data cannot be flushed to the client. The %T prints the concrete writer type that lacks Flusher.

Source

Thrown at response.go:85

			r.Status = http.StatusOK
		}
		r.WriteHeader(r.Status)
	}
	n, err = r.ResponseWriter.Write(b)
	r.Size += int64(n)
	for _, fn := range r.afterFuncs {
		fn()
	}
	return
}

// Flush implements the http.Flusher interface to allow an HTTP handler to flush
// buffered data to the client.
// See [http.Flusher](https://golang.org/pkg/net/http/#Flusher)
func (r *Response) Flush() {
	err := http.NewResponseController(r.ResponseWriter).Flush()
	if err != nil && errors.Is(err, http.ErrNotSupported) {
		panic(fmt.Errorf("echo: response writer %T does not support flushing (http.Flusher interface)", r.ResponseWriter))
	}
}

// Hijack implements the http.Hijacker interface to allow an HTTP handler to
// take over the connection.
// This method is relevant to Websocket connection upgrades, proxis, and other advanced use cases.
// See [http.Hijacker](https://golang.org/pkg/net/http/#Hijacker)
func (r *Response) Hijack() (net.Conn, *bufio.ReadWriter, error) {
	// newer code should do response hijacking like that
	// http.NewResponseController(responseWriter).Hijack()
	//
	// but there are older libraries that are not aware of `http.NewResponseController` and try to hijack directly
	// `hj, ok := resp.(http.Hijacker)` <-- which would fail without Response directly implementing Hijack method
	// so for that purpose we need to implement http.Hijacker interface
	return http.NewResponseController(r.ResponseWriter).Hijack()
}

// Unwrap returns the original http.ResponseWriter.

View on GitHub (pinned to 05489dc173)

Solutions

  1. Ensure the ResponseWriter chain implements http.Flusher (the default net/http writer does).
  2. In tests, use a real http.Server/httptest.Server rather than ResponseRecorder for streaming endpoints.
  3. When wrapping echo.Response, embed the underlying writer so Flusher/Hijacker are preserved, or forward Flush explicitly.

Example fix

// before: custom wrapper drops Flusher
type myWriter struct{ http.ResponseWriter }
func(w *myWriter) Write(b []byte)(int,error){ return w.ResponseWriter.Write(b) }
// after: forward Flusher explicitly
func (w *myWriter) Flush() {
    if f, ok := w.ResponseWriter.(http.Flusher); ok { f.Flush() }
}
Defensive patterns

Strategy: type-guard

Type guard

// Verify the response writer supports flushing before calling Flush (e.g. in SSE handlers).
func canFlush(w http.ResponseWriter) bool {
    _, ok := w.(http.Flusher)
    return ok
}

// usage
if !canFlush(c.Response().Writer) {
    return echo.NewHTTPError(http.StatusNotImplemented, "streaming not supported")
}

Try / catch

// Recover from the Flush panic in streaming handlers if the writer may not flush.
defer func() {
    if r := recover(); r != nil {
        c.Error(echo.NewHTTPError(http.StatusNotImplemented, "response writer does not support flushing"))
    }
}()
c.Response().Flush()

Prevention

When it happens

Trigger: Calling c.Response().Flush() (or any code path that flushes, e.g. SSE streaming) when the underlying ResponseWriter does not implement http.Flusher. Common with httptest.ResponseRecorder in tests, or custom writer wrappers that don't forward the Flusher interface.

Common situations: Server-Sent Events handlers tested with httptest.ResponseRecorder; middleware that decorates the Response with a writer missing Flusher; running under a server adapter that doesn't expose Flusher.

Related errors


AI-assisted analysis of labstack/echo@05489dc173 (2026-08-04). Data as JSON: /data/errors/656b86b07a0b3b2b.json. Report an issue: GitHub.