{"record":{"id":"7c5022f0d4fd09fd","repo":"valyala/fasthttp","slug":"panic-while-writing-body-stream-v","errorCode":null,"errorMessage":"panic while writing body stream: %+v","messagePattern":"panic while writing body stream: %\\+v","errorType":"panic","errorClass":"ErrBodyStreamWritePanic","httpStatus":null,"severity":"error","filePath":"http.go","lineNumber":2350,"sourceCode":"\t\t}\n\t}\n\terrc := req.closeBodyStream()\n\tif err == nil {\n\t\terr = errc\n\t}\n\treturn err\n}\n\n// ErrBodyStreamWritePanic is returned when panic happens during writing body stream.\ntype ErrBodyStreamWritePanic struct {\n\terror\n}\n\nfunc (resp *Response) writeBodyStream(w *bufio.Writer, sendBody bool) (err error) {\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\terr = &ErrBodyStreamWritePanic{\n\t\t\t\terror: fmt.Errorf(\"panic while writing body stream: %+v\", r),\n\t\t\t}\n\t\t}\n\t}()\n\n\tcontentLength := resp.Header.ContentLength()\n\tif contentLength < 0 {\n\t\tlrSize := limitedReaderSize(resp.bodyStream)\n\t\tif lrSize >= 0 {\n\t\t\tcontentLength = int(lrSize)\n\t\t\tif int64(contentLength) != lrSize {\n\t\t\t\tcontentLength = -1\n\t\t\t}\n\t\t\tif contentLength >= 0 {\n\t\t\t\tresp.Header.SetContentLength(contentLength)\n\t\t\t}\n\t\t}\n\t}\n\tif contentLength >= 0 {","sourceCodeStart":2332,"sourceCodeEnd":2368,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/http.go#L2332-L2368","documentation":"When a response body is a stream (BodyStream set), fasthttp writes it inside a recover guard; if the stream's Write panics, the panic is converted into an ErrBodyStreamWritePanic wrapping this message plus the recovered value. This prevents a user-supplied stream panic from crashing the server/client goroutine.","triggerScenarios":"Setting resp.SetBodyStream(reader, size) (server or client) where the reader's Read or the wrapper Write panics — nil map access, index out of range, or a nil reader dereference inside custom streaming code.","commonSituations":"Streaming from a generator function that panics on exhaustion; passing a reader that panics when read after Close; data races on shared state accessed inside the stream's Read.","solutions":["Fix the panicking code in your BodyStream reader/writer (inspect the %+v value for the panic message and stack hint).","Recover inside your own stream implementation and return an error from Read instead of panicking.","Verify the size hint passed to SetBodyStream matches reality to avoid mismatched writes.","Test streams with concurrent Close/Read to surface races (go test -race)."],"exampleFix":"// before\nresp.SetBodyStream(riskyReader, -1) // riskyReader panics on EOF\n// after\nresp.SetBodyStream(safeReader{r: riskyReader}, -1)\n\ntype safeReader struct{ r io.Reader }\nfunc (s safeReader) Read(p []byte) (int, error) {\n    defer func() { if r := recover(); r != nil { /* log */ } }()\n    return s.r.Read(p)\n}","handlingStrategy":"try-catch","validationCode":"if r == nil { return errors.New(\"nil body stream reader\") }","typeGuard":"func nonPanicReader(r io.Reader) io.Reader {\n    return panicSafeReader{r}\n}\ntype panicSafeReader struct{ io.Reader }\nfunc (p panicSafeReader) Read(b []byte) (n int, err error) {\n    defer func() {\n        if rec := recover(); rec != nil {\n            err = fmt.Errorf(\"stream read panic: %v\", rec)\n        }\n    }()\n    return p.Reader.Read(b)\n}","tryCatchPattern":"// fasthttp already converts panics; handle the typed error\nif err := ctx.Write(respBody); err != nil {\n    var pe *fasthttp.ErrBodyStreamWritePanic\n    if errors.As(err, &pe) {\n        log.Printf(\"body stream panicked: %v\", pe.Unwrap())\n    }\n    return err\n}","preventionTips":["Never let stream readers dereference nil or index out of range","Guard shared state accessed inside stream Read (data races)","Return errors from Read instead of panicking","Test streams under -race and with early client disconnects"],"tags":["panic","body-stream","streaming"],"backgroundTag":"panic-in-body-stream","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}