{"record":{"id":"0fa4c10839e9f822","repo":"XTLS/Xray-core","slug":"trojan-settings-servers-should-have-one-and-onl","errorCode":null,"errorMessage":"Trojan settings: \"servers\" should have one and only one member. Multiple endpoints in \"servers\" should use multiple Trojan outbounds and routing balancer instead","messagePattern":"Trojan settings: \"servers\" should have one and only one member\\. Multiple endpoints in \"servers\" should use multiple Trojan outbounds and routing balancer instead","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/trojan.go","lineNumber":58,"sourceCode":"\n// Build implements Buildable\nfunc (c *TrojanClientConfig) Build() (proto.Message, error) {\n\terrors.PrintNonRemovalDeprecatedFeatureWarning(\"Trojan (with no Flow, etc.)\", \"VLESS with Flow & Seed\")\n\n\tif c.Address != nil {\n\t\tc.Servers = []*TrojanServerTarget{\n\t\t\t{\n\t\t\t\tAddress:  c.Address,\n\t\t\t\tPort:     c.Port,\n\t\t\t\tLevel:    c.Level,\n\t\t\t\tEmail:    c.Email,\n\t\t\t\tPassword: c.Password,\n\t\t\t\tFlow:     c.Flow,\n\t\t\t},\n\t\t}\n\t}\n\tif len(c.Servers) != 1 {\n\t\treturn nil, errors.New(`Trojan settings: \"servers\" should have one and only one member. Multiple endpoints in \"servers\" should use multiple Trojan outbounds and routing balancer instead`)\n\t}\n\n\tconfig := &trojan.ClientConfig{}\n\n\tfor _, rec := range c.Servers {\n\t\tif rec.Address == nil {\n\t\t\treturn nil, errors.New(\"Trojan server address is not set.\")\n\t\t}\n\t\tif rec.Port == 0 {\n\t\t\treturn nil, errors.New(\"Invalid Trojan port.\")\n\t\t}\n\t\tif rec.Password == \"\" {\n\t\t\treturn nil, errors.New(\"Trojan password is not specified.\")\n\t\t}\n\t\tif rec.Flow != \"\" {\n\t\t\treturn nil, errors.PrintRemovedFeatureError(`Flow for Trojan`, ``)\n\t\t}\n","sourceCodeStart":40,"sourceCodeEnd":76,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/trojan.go#L40-L76","documentation":"Thrown when building a Trojan client config: after the legacy single-server fields are normalized into c.Servers, the list must contain exactly one entry. Multiple servers in one outbound are rejected by design — each endpoint needs its own Trojan outbound plus a routing balancer.","triggerScenarios":"Writing \"settings\": { \"servers\": [ {...}, {...} ] } with two or more server objects in a Trojan outbound; or an empty servers array.","commonSituations":"Migrating a client config that lists several Trojan nodes for 'failover' in one outbound — the Trojan client protocol connects to a single endpoint, so this pattern is not supported.","solutions":["Keep exactly one server object in the Trojan outbound's \"servers\"","For multiple endpoints, create one Trojan outbound per server and distribute traffic with a routing \"balancer\" section","Point a load-balancer/health-check layer in front and expose a single address to Xray"],"exampleFix":"// before\n\"servers\": [ {\"address\":\"a.example\",\"port\":443,...}, {\"address\":\"b.example\",\"port\":443,...} ]\n// after\n// outbound[0]: trojan -> a.example ; outbound[1]: trojan -> b.example ; routing.balancer tags both","handlingStrategy":"validation","validationCode":"servers := gjson.Get(config, \"outbounds.#(protocol=trojan).settings.servers\").Array()\nif len(servers) != 1 {\n    return errors.New(\"trojan outbound must have exactly one server; use multiple outbounds + balancer\")\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Model 'one outbound per endpoint' in config templates from the start","Use routing balancers for multi-endpoint Trojan, never a multi-element servers array"],"tags":["config","trojan","outbound","balancer"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}