{"record":{"id":"9419953515bbd6bd","repo":"cloudflare/cloudflared","slug":"t-doesn-t-implement-http-flusher","errorCode":null,"errorMessage":"%T doesn't implement http.Flusher","messagePattern":"%T doesn't implement http\\.Flusher","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"connection/http2.go","lineNumber":214,"sourceCode":"\tw             http.ResponseWriter\n\tflusher       http.Flusher\n\tshouldFlush   bool\n\tstatusWritten bool\n\trespHeaders   http.Header\n\thijackedMutex sync.Mutex\n\thijackedv     bool\n\tlog           *zerolog.Logger\n}\n\nfunc NewHTTP2RespWriter(r *http.Request, w http.ResponseWriter, connType Type, log *zerolog.Logger) (*http2RespWriter, error) {\n\tflusher, isFlusher := w.(http.Flusher)\n\tif !isFlusher {\n\t\trespWriter := &http2RespWriter{\n\t\t\tr:   r.Body,\n\t\t\tw:   w,\n\t\t\tlog: log,\n\t\t}\n\t\terr := fmt.Errorf(\"%T doesn't implement http.Flusher\", w)\n\t\trespWriter.WriteErrorResponse(err)\n\t\treturn nil, err\n\t}\n\n\treturn &http2RespWriter{\n\t\tr:           r.Body,\n\t\tw:           w,\n\t\tflusher:     flusher,\n\t\tshouldFlush: connType.shouldFlush(),\n\t\trespHeaders: make(http.Header),\n\t\tlog:         log,\n\t}, nil\n}\n\nfunc (rp *http2RespWriter) AddTrailer(trailerName, trailerValue string) {\n\tif !rp.statusWritten {\n\t\trp.log.Warn().Msg(\"Tried to add Trailer to response before status written. Ignoring...\")\n\t\treturn","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/connection/http2.go#L196-L232","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\ntype noFlushWriter struct{ http.ResponseWriter }\n// after\ntype flushingWriter struct{ http.ResponseWriter }\nfunc (w *flushingWriter) Flush() { w.ResponseWriter.(http.Flusher).Flush() }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func asFlusher(w http.ResponseWriter) (http.Flusher, bool) {\n    f, ok := w.(http.Flusher)\n    return f, ok\n}","tryCatchPattern":"if _, ok := w.(http.Flusher); !ok {\n    // don't hand w to code needing streaming; use a buffered non-streaming path instead\n}","preventionTips":["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"],"tags":["http","interface","flusher","streaming"],"backgroundTag":"method-not-implemented","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}