{"record":{"id":"27faff3043a63a03","repo":"ginuerzh/gost","slug":"write-not-supported-27faff","errorCode":null,"errorMessage":"write not supported","messagePattern":"write not supported","errorType":"error_code","errorClass":"net.OpError","httpStatus":null,"severity":"error","filePath":"http2.go","lineNumber":894,"sourceCode":"}\n\nfunc (c *http2Conn) SetWriteDeadline(t time.Time) error {\n\treturn &net.OpError{Op: \"set\", Net: \"http2\", Source: nil, Addr: nil, Err: errors.New(\"deadline not supported\")}\n}\n\n// a dummy HTTP2 server conn used by HTTP2 handler\ntype http2ServerConn struct {\n\tr      *http.Request\n\tw      http.ResponseWriter\n\tclosed chan struct{}\n}\n\nfunc (c *http2ServerConn) Read(b []byte) (n int, err error) {\n\treturn 0, &net.OpError{Op: \"read\", Net: \"http2\", Source: nil, Addr: nil, Err: errors.New(\"read not supported\")}\n}\n\nfunc (c *http2ServerConn) Write(b []byte) (n int, err error) {\n\treturn 0, &net.OpError{Op: \"write\", Net: \"http2\", Source: nil, Addr: nil, Err: errors.New(\"write not supported\")}\n}\n\nfunc (c *http2ServerConn) Close() error {\n\tselect {\n\tcase <-c.closed:\n\tdefault:\n\t\tclose(c.closed)\n\t}\n\treturn nil\n}\n\nfunc (c *http2ServerConn) LocalAddr() net.Addr {\n\taddr, _ := net.ResolveTCPAddr(\"tcp\", c.r.Host)\n\treturn addr\n}\n\nfunc (c *http2ServerConn) RemoteAddr() net.Addr {\n\taddr, _ := net.ResolveTCPAddr(\"tcp\", c.r.RemoteAddr)","sourceCodeStart":876,"sourceCodeEnd":912,"githubUrl":"https://github.com/ginuerzh/gost/blob/a33fdbf4c98034f4bfeeaea9868909822b9c526d/http2.go#L876-L912","documentation":"http2ServerConn.Write is a stub returning a *net.OpError with \"write not supported\", because writes must go through the wrapped http.ResponseWriter rather than a raw byte sink. The dummy conn only exposes Close/addr/deadline behavior for interface compatibility.","triggerScenarios":"Calling Write() on an http2ServerConn, e.g. relaying bytes with io.Copy(serverConn, src) or writing handshake payloads directly to the conn.","commonSituations":"Treating the handler-side conn as a bidirectional tunnel; porting code from a TCP-based handler where conn.Write worked; forgetting that HTTP/2 response data must be written to the ResponseWriter with proper headers flushed.","solutions":["Write response data via c.w (http.ResponseWriter), after flushing headers with the http.Flusher.","Use http2Conn from the listener/dialer path for raw conn writes (it backs onto an HTTP/2 stream pipe).","Replace conn-based relay writes with a pipe: write into an io.Pipe handed to the ResponseWriter.","Type-check before writing so the dummy server conn is never passed to byte-oriented code."],"exampleFix":"// before\nserverConn.Write(buf) // write not supported\n// after\nserverConn.w.Write(buf) // write via the underlying ResponseWriter\nif fw, ok := serverConn.w.(http.Flusher); ok { fw.Flush() }","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"func isUnsupportedWrite(err error) bool {\n    var oe *net.OpError\n    return errors.As(err, &oe) && oe.Net == \"http2\" && strings.Contains(err.Error(), \"write not supported\")\n}","tryCatchPattern":"if _, err := conn.Write(b); err != nil {\n    if isUnsupportedWrite(err) {\n        return fmt.Errorf(\"write via http.ResponseWriter, not the dummy server conn\")\n    }\n    return err\n}","preventionTips":["Route all response writes through the wrapped http.ResponseWriter and flush headers.","Do not pass handler-side dummy conns into relay/tunnel write paths.","Type-assert conns before handing them to byte-oriented helpers."],"tags":["http2","write","unsupported-operation","net-conn"],"backgroundTag":"operation-not-supported","analyzedSha":"a33fdbf4c98034f4bfeeaea9868909822b9c526d","analyzedAt":"2026-09-02T22:15:54.506Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}