cloudflare/cloudflared · error
%T doesn't implement http.Flusher
Error message
%T doesn't implement http.Flusher
What it means
NewHTTP2RespWriter requires the http.ResponseWriter to also implement http.Flusher so it can flush streamed responses (SSE, websockets). If the writer does not, it builds an error `%T doesn't implement http.Flusher`, writes an error response on that writer, and returns nil, err. Callers (ServeHTTP/proxy helpers) then abort the request.
Source
Thrown at connection/http2.go:214
w http.ResponseWriter
flusher http.Flusher
shouldFlush bool
statusWritten bool
respHeaders http.Header
hijackedMutex sync.Mutex
hijackedv bool
log *zerolog.Logger
}
func NewHTTP2RespWriter(r *http.Request, w http.ResponseWriter, connType Type, log *zerolog.Logger) (*http2RespWriter, error) {
flusher, isFlusher := w.(http.Flusher)
if !isFlusher {
respWriter := &http2RespWriter{
r: r.Body,
w: w,
log: log,
}
err := fmt.Errorf("%T doesn't implement http.Flusher", w)
respWriter.WriteErrorResponse(err)
return nil, err
}
return &http2RespWriter{
r: r.Body,
w: w,
flusher: flusher,
shouldFlush: connType.shouldFlush(),
respHeaders: make(http.Header),
log: log,
}, nil
}
func (rp *http2RespWriter) AddTrailer(trailerName, trailerValue string) {
if !rp.statusWritten {
rp.log.Warn().Msg("Tried to add Trailer to response before status written. Ignoring...")
returnView on GitHub (pinned to 2253eeeb25)
Solutions
- If using custom middleware, make the wrapper implement http.Flusher by delegating Flush() to the inner writer
- In tests, use a writer that implements http.Flusher (httptest.ResponseRecorder does not, wrap it)
- Ensure the middleware passes http.ResponseWriter through unmodified when possible
- Upgrade cloudflared if this appears in stock proxying paths
Example fix
// before
type noFlushWriter struct{ http.ResponseWriter }
// after
type flushingWriter struct{ http.ResponseWriter }
func (w *flushingWriter) Flush() { w.ResponseWriter.(http.Flusher).Flush() } Defensive patterns
Strategy: type-guard
Type guard
func asFlusher(w http.ResponseWriter) (http.Flusher, bool) {
f, ok := w.(http.Flusher)
return f, ok
} Try / catch
if _, ok := w.(http.Flusher); !ok {
// don't hand w to code needing streaming; use a buffered non-streaming path instead
} Prevention
- Never wrap http.ResponseWriter in middleware that drops the Flusher interface
- Implement Flush() on custom wrapper types
- Test streaming endpoints (SSE/websocket) through any middleware you add
When it happens
Trigger: NewHTTP2RespWriter is called with an http.ResponseWriter whose concrete type lacks a Flush() method — i.e. the edge/http2 stack supplied a non-flushing writer, or a test/proxy wrapper implements only http.ResponseWriter.
Common situations: Custom middleware wrapping the ResponseWriter without forwarding Flush(), test harnesses using httptest writers without Flusher support, or an http2 transport regression in the library itself.
Related errors
- ErrAPINoSuccess
- Failed to fetch page. Server returned: %d
- internal error: unsupported connection type
- API errors: %s
- quick tunnel provisioning failed with status %d: %s
AI-assisted analysis of cloudflare/cloudflared@2253eeeb25 (2026-09-06).
Data as JSON: /api/errors/9419953515bbd6bd.
Report an issue: GitHub.