{"record":{"id":"1c194ef0155247e1","repo":"valyala/fasthttp","slug":"pipeline-connection-has-been-stopped","errorCode":null,"errorMessage":"pipeline connection has been stopped","messagePattern":"pipeline connection has been stopped","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"client.go","lineNumber":3333,"sourceCode":"\tn := 0\n\tfor _, cc := range c.connClients {\n\t\tn += cc.PendingRequests()\n\t}\n\tc.connClientsLock.Unlock()\n\treturn n\n}\n\nfunc (c *pipelineConnClient) PendingRequests() int {\n\tchs := c.acquirePipelineConnChannels()\n\tdefer c.releasePipelineConnChannels(chs)\n\n\tc.chLock.Lock()\n\tn := len(chs.chR) + len(chs.chW)\n\tc.chLock.Unlock()\n\treturn n\n}\n\nvar errPipelineConnStopped = errors.New(\"pipeline connection has been stopped\")\n\nvar DefaultTransport RoundTripper = &transport{}\n\ntype transport struct{}\n\n// clientStreamBody serializes reads and keeps pooled response resources alive\n// until an in-flight Read has returned. interrupt must unblock network reads\n// without releasing the connection wrapper or reader pools; release performs\n// that cleanup afterward.\ntype clientStreamBody struct {\n\treader    io.Reader\n\tinterrupt func()\n\trelease   func(bool)\n\tclosed    atomic.Bool\n\tfullyRead bool\n\treadLock  sync.Mutex\n\tcloseOnce sync.Once\n}","sourceCodeStart":3315,"sourceCodeEnd":3351,"githubUrl":"https://github.com/valyala/fasthttp/blob/c96f600972c6f4a7a30d664257b340ebe9d60124/client.go#L3315-L3351","documentation":"errPipelineConnStopped is an internal error returned by a PipelineClient's per-connection worker when the connection has been stopped (client closed or connection reset). Any request whose response channel was waiting is completed with this error. It means the pipeline connection was torn down while work was in flight.","triggerScenarios":"Calling PipelineClient.Do* concurrently with PipelineClient.Stop(), or after Stop(); the internal pipeline goroutine exiting (server closed the connection) while requests are still queued in chs.chR/chs.chW.","commonSituations":"Application shutting down a PipelineClient while background goroutines still issue requests; server dropping keep-alive pipeline connections mid-flight; race between Stop() and in-flight Do() calls.","solutions":["Ensure PipelineClient.Stop() is called only after all in-flight Do* calls finish (use WaitGroup)","Retry the request on a fresh PipelineClient when this error is received","Check server logs for connection resets / idle timeouts that kill the pipeline connection","Handle this error explicitly in shutdown code instead of treating it as fatal"],"exampleFix":"// before\ngo func() { client.Do(req, resp) }()\nclient.Stop()\n// after\nvar wg sync.WaitGroup\nwg.Add(1)\ngo func() { defer wg.Done(); client.Do(req, resp) }()\nwg.Wait()\nclient.Stop()","handlingStrategy":"try-catch","validationCode":null,"typeGuard":"func isPipelineStopped(err error) bool {\n    return errors.Is(err, fasthttp.ErrPipelineOverflow) || err != nil && strings.Contains(err.Error(), \"pipeline connection has been stopped\")\n}","tryCatchPattern":"if err := pc.Do(req, resp); err != nil && isPipelineStopped(err) {\n    pc = newPipelineClient() // recreate after Stop\n}","preventionTips":["Join all request goroutines before calling Stop()","Use WaitGroups or context cancellation around Do calls","Recreate PipelineClient after Stop instead of reusing it","Log connection resets from the server side"],"tags":["fasthttp","pipelining","connection-closed","shutdown"],"backgroundTag":"connection-closed","analyzedSha":"c96f600972c6f4a7a30d664257b340ebe9d60124","analyzedAt":"2026-08-31T22:48:28.265Z","contentChangedAt":null,"schemaVersion":2},"datasetVersion":"2026-09-08T05:18:18.240Z"}