{"record":{"id":"0f7229d223ad90d8","repo":"XTLS/Xray-core","slug":"no-mux-client-worker-available","errorCode":null,"errorMessage":"no mux client worker available","messagePattern":"no mux client worker available","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"app/reverse/portal.go","lineNumber":214,"sourceCode":"\t}\n\n\tif minIdx == -1 {\n\t\tfor i, w := range p.workers {\n\t\t\tif w.IsFull() {\n\t\t\t\tcontinue\n\t\t\t}\n\t\t\tif w.client.ActiveConnections() < minConn {\n\t\t\t\tminConn = w.client.ActiveConnections()\n\t\t\t\tminIdx = i\n\t\t\t}\n\t\t}\n\t}\n\n\tif minIdx != -1 {\n\t\treturn p.workers[minIdx].client, nil\n\t}\n\n\treturn nil, errors.New(\"no mux client worker available\")\n}\n\nfunc (p *StaticMuxPicker) AddWorker(worker *PortalWorker) {\n\tp.access.Lock()\n\tdefer p.access.Unlock()\n\n\tp.workers = append(p.workers, worker)\n}\n\ntype PortalWorker struct {\n\tclient   *mux.ClientWorker\n\tcontrol  *task.Periodic\n\twriter   buf.Writer\n\treader   buf.Reader\n\tdraining bool\n\tcounter  uint32\n\ttimer    *signal.ActivityTimer\n}","sourceCodeStart":196,"sourceCodeEnd":232,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/app/reverse/portal.go#L196-L232","documentation":"StaticMuxPicker.PickAvailable found workers in the pool but none usable: every registered PortalWorker was skipped because w.draining is true (worker closing, removed after inactivity/24h timer) or w.IsFull() is true (mux worker hit its connection/cool-down capacity, hysteresis full state). Unlike error 93, the bridge tunnels exist — they are just saturated or draining.","triggerScenarios":"All workers simultaneously in draining or IsFull state at pick time: a burst of tunneled connections filling each mux worker's connection limit, or a mass reconnect draining old workers while new ones have not been added yet.","commonSituations":"Heavy load through a single bridge connection (all tunneled streams multiplexed over it until capacity), bridge reconnect storms marking old workers draining, or too few bridges for the offered load. Users see intermittent 'no mux client worker available' during peaks.","solutions":["Add more bridges in the reverse config so the picker can spread connections and always find a non-full worker.","Reduce multiplexing pressure: lower concurrent tunneled connections, or route bulk traffic outside the tunnel.","If it appears right after restarts, wait for the bridge to re-register a fresh worker (monitor interval ~2s) and confirm errors 91-95 are not firing."],"exampleFix":"// before\n\"reverse\": { \"portals\": [ { \"tag\": \"portal\", \"domain\": \"svc.reverse.internal\" } ],\n            \"bridges\": [ { \"tag\": \"bridge-1\", \"domain\": \"svc.reverse.internal\" } ] }\n\n// after: add capacity\n\"reverse\": { \"portals\": [ { \"tag\": \"portal\", \"domain\": \"svc.reverse.internal\" } ],\n            \"bridges\": [ { \"tag\": \"bridge-1\", \"domain\": \"svc.reverse.internal\" },\n                          { \"tag\": \"bridge-2\", \"domain\": \"svc2.reverse.internal\" } ] }","handlingStrategy":"fallback","validationCode":"// Capacity pre-check: at least one non-draining, non-full worker\nif !picker.HasAvailable() { // iterate workers: !draining && !IsFull()\n    return routeViaAlternatePath(ctx, link)\n}","typeGuard":"func pickerHasCapacity(picker reverse.WorkerCounter) bool {\n    return picker.HasAvailable() // false when all workers draining or IsFull()\n}","tryCatchPattern":"if err := dispatch(ctx, link); err != nil {\n    if strings.Contains(err.Error(), \"no mux client worker available\") {\n        return retryWithBackoff(ctx, link, attempts=3) // workers free up / re-register quickly\n    }\n    return err\n}","preventionTips":["Scale bridge count with offered tunneled-connection load","Watch worker saturation metrics; add bridges before peak hours","During reconnect storms, drain old workers only after new ones register (capacity-aware ops)"],"tags":["go","xray","reverse-proxy","mux","capacity"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}