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

  1. Keep exactly one server object in the Trojan outbound's "servers"
  2. For multiple endpoints, create one Trojan outbound per server and distribute traffic with a routing "balancer" section
  3. 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

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


AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15). Data as JSON: /api/errors/0fa4c10839e9f822. Report an issue: GitHub.