ginuerzh/gost · warning
s
Error message
s
What it means
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.
Source
Thrown at http2.go:951
onClose func()
}
func (c *http2ClientConn) Close() error {
if c.onClose != nil {
c.onClose()
}
return nil
}
type flushWriter struct {
w io.Writer
}
func (fw flushWriter) Write(p []byte) (n int, err error) {
defer func() {
if r := recover(); r != nil {
if s, ok := r.(string); ok {
err = errors.New(s)
log.Log("[http2]", err)
return
}
err = r.(error)
}
}()
n, err = fw.w.Write(p)
if err != nil {
// log.Log("flush writer:", err)
return
}
if f, ok := fw.w.(http.Flusher); ok {
f.Flush()
}
return
}
View on GitHub (pinned to a33fdbf4c9)
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.
Defensive patterns
Strategy: try-catch
Validate before calling
if w == nil || responseWriterClosed(req) {
return errors.New("flush writer unavailable")
} Type guard
func validFlushTarget(w http.ResponseWriter) bool {
if w == nil { return false }
type f interface{ Flush() }
_, ok := w.(f)
return ok
} Try / catch
// flushWriter already recovers; at call site check the returned error
n, err := fw.Write(p)
if err != nil {
log.Printf("[http2] flush failed: %v", err)
// abort stream / close conn
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Related errors
AI-assisted analysis of ginuerzh/gost@a33fdbf4c9 (2026-09-02).
Data as JSON: /api/errors/d821378a91634c54.
Report an issue: GitHub.