XTLS/Xray-core · error
Trojan settings: "servers" should have one and only one memb
Error message
Trojan settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple Trojan outbounds and routing balancer instead
What it means
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.
Source
Thrown at infra/conf/trojan.go:58
// Build implements Buildable
func (c *TrojanClientConfig) Build() (proto.Message, error) {
errors.PrintNonRemovalDeprecatedFeatureWarning("Trojan (with no Flow, etc.)", "VLESS with Flow & Seed")
if c.Address != nil {
c.Servers = []*TrojanServerTarget{
{
Address: c.Address,
Port: c.Port,
Level: c.Level,
Email: c.Email,
Password: c.Password,
Flow: c.Flow,
},
}
}
if len(c.Servers) != 1 {
return 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`)
}
config := &trojan.ClientConfig{}
for _, rec := range c.Servers {
if rec.Address == nil {
return nil, errors.New("Trojan server address is not set.")
}
if rec.Port == 0 {
return nil, errors.New("Invalid Trojan port.")
}
if rec.Password == "" {
return nil, errors.New("Trojan password is not specified.")
}
if rec.Flow != "" {
return nil, errors.PrintRemovedFeatureError(`Flow for Trojan`, ``)
}
View on GitHub (pinned to 7d214f8b09)
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
Example fix
// before
"servers": [ {"address":"a.example","port":443,...}, {"address":"b.example","port":443,...} ]
// after
// outbound[0]: trojan -> a.example ; outbound[1]: trojan -> b.example ; routing.balancer tags both Defensive patterns
Strategy: validation
Validate before calling
servers := gjson.Get(config, "outbounds.#(protocol=trojan).settings.servers").Array()
if len(servers) != 1 {
return errors.New("trojan outbound must have exactly one server; use multiple outbounds + balancer")
} Prevention
- Model 'one outbound per endpoint' in config templates from the start
- Use routing balancers for multi-endpoint Trojan, never a multi-element servers array
When it happens
Trigger: Writing "settings": { "servers": [ {...}, {...} ] } with two or more server objects in a Trojan outbound; or an empty servers array.
Common situations: 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.
Related errors
- Shadowsocks settings: "servers" should have one and only one
- SOCKS settings: "servers" should have one and only one membe
- VLESS settings: "vnext" should have one and only one member.
- VMess settings: "vnext" should have one and only one member.
- no target server found
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/0fa4c10839e9f822.
Report an issue: GitHub.