{"record":{"id":"861242cf886534ba","repo":"MHSanaei/3x-ui","slug":"too-many-outbounds-in-one-request-max-d","errorCode":null,"errorMessage":"too many outbounds in one request (max %d)","messagePattern":"too many outbounds in one request \\(max (.+?)\\)","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"internal/web/service/outbound/probe_http.go","lineNumber":129,"sourceCode":"\tvar ob map[string]any\n\tif err := json.Unmarshal([]byte(outboundJSON), &ob); err != nil {\n\t\treturn &TestOutboundResult{Mode: probeModeLabel(mode), Success: false, Error: fmt.Sprintf(\"Invalid outbound JSON: %v\", err)}, nil\n\t}\n\tresults := s.testOutboundsParsed([]map[string]any{ob}, testURL, allOutboundsJSON, mode)\n\treturn results[0], nil\n}\n\n// TestOutbounds probes a JSON array of outbounds and returns one result per\n// input, in input order, each carrying the outbound's tag. allOutboundsJSON\n// supplies the config context (sockopt.dialerProxy chains); testURL falls\n// back to the default probe URL when empty.\nfunc (s *OutboundService) TestOutbounds(outboundsJSON string, testURL string, allOutboundsJSON string, mode string) ([]*TestOutboundResult, error) {\n\tvar raw []json.RawMessage\n\tif err := json.Unmarshal([]byte(outboundsJSON), &raw); err != nil {\n\t\treturn nil, fmt.Errorf(\"invalid outbounds JSON: %w\", err)\n\t}\n\tif len(raw) > maxBatchItems {\n\t\treturn nil, fmt.Errorf(\"too many outbounds in one request (max %d)\", maxBatchItems)\n\t}\n\titems := make([]map[string]any, len(raw))\n\tfor i, r := range raw {\n\t\tvar ob map[string]any\n\t\tif err := json.Unmarshal(r, &ob); err == nil {\n\t\t\titems[i] = ob\n\t\t}\n\t}\n\treturn s.testOutboundsParsed(items, testURL, allOutboundsJSON, mode), nil\n}\n\n// testOutboundsParsed splits items into the TCP lane (direct dials, bounded\n// worker pool) and the HTTP lane (one shared temp xray instance), runs both,\n// and returns results aligned with items. A nil item marks unparseable input.\nfunc (s *OutboundService) testOutboundsParsed(items []map[string]any, testURL string, allOutboundsJSON string, mode string) []*TestOutboundResult {\n\tresults := make([]*TestOutboundResult, len(items))\n\n\tmodeLabel := probeModeLabel(mode)","sourceCodeStart":111,"sourceCodeEnd":147,"githubUrl":"https://github.com/MHSanaei/3x-ui/blob/ad32144c42455696ea9f14e12168beac3e25f5d2/internal/web/service/outbound/probe_http.go#L111-L147","documentation":"TestOutbounds caps one request at maxBatchItems (50) outbounds to bound the probe batch: each item gets its own loopback port and inbounds entry in a shared xray test process. Exceeding the cap fails the whole request before any probing starts.","triggerScenarios":"Sending an array of 51+ outbounds to the batch test endpoint/API in one call.","commonSituations":"Selecting 'test all' on a large outbound list where the client batches everything into one request; migrating a big config and probing it wholesale.","solutions":["Split the request into chunks of at most 50 outbounds and aggregate the results client-side","Filter to only the outbounds you actually need tested before batching"],"exampleFix":"// before\nresults, err := svc.TestOutbounds(allOutboundsJSON, url, ctx, mode) // 120 items\n\n// after\nconst chunk = 50\nfor i := 0; i < len(items); i += chunk {\n    end := min(i+chunk, len(items))\n    part, _ := svc.TestOutbounds(marshal(items[i:end]), url, ctx, mode)\n    results = append(results, part...)\n}","handlingStrategy":"validation","validationCode":"const maxBatch = 50\nvar items []json.RawMessage\n_ = json.Unmarshal([]byte(outboundsJSON), &items)\nif len(items) > maxBatch {\n    // split client-side before calling\n    outboundsJSON = marshalN(items, maxBatch)\n}\nresults, err := svc.TestOutbounds(outboundsJSON, ...)","typeGuard":null,"tryCatchPattern":"results, err := svc.TestOutbounds(payload, ...)\nif err != nil && strings.Contains(err.Error(), \"too many outbounds\") {\n    // chunk and retry; aggregate results\n}","preventionTips":["Frontend: disable 'test all' above 50 items or chunk automatically","Keep the maxBatchItems constant in sync with UI copy"],"tags":["limits","outbounds","batching","api"],"backgroundTag":null,"analyzedSha":"ad32144c42455696ea9f14e12168beac3e25f5d2","analyzedAt":"2026-08-15T11:13:23.905Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}