{"record":{"id":"d88cf93caebe55df","repo":"cloudflare/cloudflared","slug":"failed-to-start-tcp-flow-due-to-rate-limiting","errorCode":null,"errorMessage":"failed to start tcp flow due to rate limiting","messagePattern":"failed to start tcp flow due to rate limiting","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"proxy/proxy.go","lineNumber":157,"sourceCode":"\t\treturn fmt.Errorf(\"unrecognized service: %s, %t\", rule.Service, originProxy)\n\t}\n}\n\n// ProxyTCP proxies to a TCP connection between the origin service and cloudflared.\nfunc (p *Proxy) ProxyTCP(\n\tctx context.Context,\n\tconn connection.ReadWriteAcker,\n\treq *connection.TCPRequest,\n) error {\n\tincrementTCPRequests()\n\tdefer decrementTCPConcurrentRequests()\n\n\tlogger := newTCPLogger(p.log, req)\n\n\t// Try to start a new flow\n\tif err := p.flowLimiter.Acquire(management.TCP.String()); err != nil {\n\t\tlogger.Warn().Msg(\"Too many concurrent flows being handled, rejecting tcp proxy\")\n\t\treturn errors.Wrap(err, \"failed to start tcp flow due to rate limiting\")\n\t}\n\tdefer p.flowLimiter.Release()\n\n\tserveCtx, cancel := context.WithCancel(ctx)\n\tdefer cancel()\n\n\ttracedCtx := tracing.NewTracedContext(serveCtx, req.CfTraceID, &logger)\n\tlogger.Debug().Msg(\"tcp proxy stream started\")\n\n\t// Parse the destination into a netip.AddrPort\n\tdest, err := netip.ParseAddrPort(req.Dest)\n\tif err != nil {\n\t\tlogRequestError(&logger, err)\n\t\treturn err\n\t}\n\n\tif err := p.proxyTCPStream(tracedCtx, conn, dest, p.originDialer, &logger); err != nil {\n\t\tlogRequestError(&logger, err)","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/cloudflare/cloudflared/blob/2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f/proxy/proxy.go#L139-L175","documentation":"ProxyTCP guards the total number of concurrent TCP flows with p.flowLimiter.Acquire(management.TCP.String()). When too many flows are already active, Acquire returns a rate-limit error which is wrapped with this message and the TCP proxy request is rejected instead of started.","triggerScenarios":"A TCP proxying request (e.g. ssh over cloudflared access tcp, or bastion mode) arrives while the flow limiter is saturated — the number of concurrent TCP flows has hit the configured cap, so Acquire fails.","commonSituations":"Many simultaneous SSH-over-tunnel sessions, leaked/unclosed TCP connections accumulating over time, or a deliberately low flow limit in a constrained deployment.","solutions":["Wait and retry — the limit is on concurrent flows; closing idle sessions frees capacity.","Find and close leaked/hung TCP sessions (check active connection lists on client and server).","Increase the flow/rate limit configuration if your workload legitimately needs more concurrent flows.","Monitor with metrics to confirm whether flows are leaking rather than just high volume."],"exampleFix":"// before (client)\nfor _, host := range hosts { go connect(host) } // bursts past flow limit\n// after\nsem := make(chan struct{}, 10)\nfor _, host := range hosts {\n    sem <- struct{}{}\n    go func(h string) { defer func() { <-sem }(); connect(h) }(host)\n}","handlingStrategy":"retry","validationCode":"// Client-side: back off when the limiter is saturated\nif strings.Contains(err.Error(), \"rate limiting\") {\n    select {\n    case <-time.After(time.Duration(rand.Intn(1000)) * time.Millisecond):\n    case <-ctx.Done():\n        return ctx.Err()\n    }\n    return retryConnect(ctx)\n}","typeGuard":null,"tryCatchPattern":"err := p.flowLimiter.Acquire(management.TCP.String())\nif err != nil {\n    logger.Warn().Err(err).Msg(\"tcp flow rejected; retry with backoff\")\n    return errors.Wrap(err, \"failed to start tcp flow due to rate limiting\")\n}\ndefer p.flowLimiter.Release()","preventionTips":["Bound client-side concurrency so you don't exhaust the remote flow limiter.","Always release acquired flows (defer Release) to avoid leaks.","Apply exponential backoff with jitter on rejection.","Raise the flow limit if legitimate workload requires it."],"tags":["tcp","rate-limit","proxy"],"backgroundTag":"rate-limit-exceeded","analyzedSha":"2253eeeb25a44a713a4b60b8ba1e1b3f377d1a0f","analyzedAt":"2026-09-06T04:14:33.757Z","contentChangedAt":"2026-09-06T04:14:33.757Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}