{"record":{"id":"d821378a91634c54","repo":"ginuerzh/gost","slug":"s","errorCode":null,"errorMessage":"s","messagePattern":"s","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"http2.go","lineNumber":951,"sourceCode":"\tonClose func()\n}\n\nfunc (c *http2ClientConn) Close() error {\n\tif c.onClose != nil {\n\t\tc.onClose()\n\t}\n\treturn nil\n}\n\ntype flushWriter struct {\n\tw io.Writer\n}\n\nfunc (fw flushWriter) Write(p []byte) (n int, err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tif s, ok := r.(string); ok {\n\t\t\t\terr = errors.New(s)\n\t\t\t\tlog.Log(\"[http2]\", err)\n\t\t\t\treturn\n\t\t\t}\n\t\t\terr = r.(error)\n\t\t}\n\t}()\n\n\tn, err = fw.w.Write(p)\n\tif err != nil {\n\t\t// log.Log(\"flush writer:\", err)\n\t\treturn\n\t}\n\tif f, ok := fw.w.(http.Flusher); ok {\n\t\tf.Flush()\n\t}\n\treturn\n}\n","sourceCodeStart":933,"sourceCodeEnd":969,"githubUrl":"https://github.com/ginuerzh/gost/blob/a33fdbf4c98034f4bfeeaea9868909822b9c526d/http2.go#L933-L969","documentation":"This is a recovered panic inside flushWriter.Write. When the embedded writer's Write panics with a string value (some libraries panic(\"...\") with strings), the deferred recover converts it into an error via errors.New(s), logs it, and returns it as the Write error instead of crashing the process.","triggerScenarios":"A Write call on the wrapped writer panics with a string (e.g. http.ErrHandlerTimeout-style panics, or bufio/http code panicking on Write after Close or on a nil/broken writer). The recover branch at http2.go:951 constructs the error from the string payload.","commonSituations":"Writing a flush to an HTTP/2 response writer after the handler has returned or after the connection was closed; races where the underlying writer becomes invalid mid-write; library code that uses panic-with-string for control flow.","solutions":["Fix the root cause panic: ensure the underlying writer is valid and not closed/nil before flushWriter.Write is called.","Inspect the logged '[http2]' message to identify the panic string and the code path that panicked.","Avoid writes after the request context/handler completes; synchronize access to the writer.","Keep the recover as a safety net but treat its error return as a failed flush and close the stream."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"if w == nil || responseWriterClosed(req) {\n\treturn errors.New(\"flush writer unavailable\")\n}","typeGuard":"func validFlushTarget(w http.ResponseWriter) bool {\n\tif w == nil { return false }\n\ttype f interface{ Flush() }\n\t_, ok := w.(f)\n\treturn ok\n}","tryCatchPattern":"// flushWriter already recovers; at call site check the returned error\nn, err := fw.Write(p)\nif err != nil {\n\tlog.Printf(\"[http2] flush failed: %v\", err)\n\t// abort stream / close conn\n}","preventionTips":["Never write to the response writer after the handler returns or the stream is reset.","Guard concurrent writes with a mutex or single-writer goroutine.","Monitor '[http2]' logs for recovered panics and fix the underlying writer lifecycle."],"tags":["http2","panic-recovery","flush","writer"],"backgroundTag":"panic-recovered-as-error","analyzedSha":"a33fdbf4c98034f4bfeeaea9868909822b9c526d","analyzedAt":"2026-09-02T22:15:54.506Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-10T02:17:09.455Z"}