XTLS/Xray-core · error
SOCKS settings: "servers" should have one and only one membe
Error message
SOCKS settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple SOCKS outbounds and routing balancer instead
What it means
The SOCKS outbound historically allowed a 'servers' array but this implementation restricts it to exactly one member (with a shorthand top-level address form normalized first). Multiple endpoints must instead be modeled as separate SOCKS outbounds plus a routing balancer; zero servers likewise fails.
Source
Thrown at infra/conf/socks.go:101
Password string `json:"pass"`
Servers []*SocksRemoteConfig `json:"servers"`
}
func (v *SocksClientConfig) Build() (proto.Message, error) {
config := new(socks.ClientConfig)
if v.Address != nil {
v.Servers = []*SocksRemoteConfig{
{
Address: v.Address,
Port: v.Port,
},
}
if len(v.Username) > 0 {
v.Servers[0].Users = []json.RawMessage{{}}
}
}
if len(v.Servers) != 1 {
return nil, errors.New(`SOCKS settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple SOCKS outbounds and routing balancer instead`)
}
for _, serverConfig := range v.Servers {
if len(serverConfig.Users) > 1 {
return nil, errors.New(`SOCKS servers: "users" should have one member at most. Multiple members in "users" should use multiple SOCKS outbounds and routing balancer instead`)
}
server := &protocol.ServerEndpoint{
Address: serverConfig.Address.Build(),
Port: uint32(serverConfig.Port),
}
for _, rawUser := range serverConfig.Users {
user := new(protocol.User)
if v.Address != nil {
user.Level = v.Level
user.Email = v.Email
} else {
if err := json.Unmarshal(rawUser, user); err != nil {
return nil, errors.New("failed to parse Socks user").Base(err).AtError()
}View on GitHub (pinned to 7d214f8b09)
Solutions
- Keep exactly one server in 'servers', or use the shorthand form with top-level 'address'/'port'/'users'.
- For multiple upstream proxies, define one SOCKS outbound per endpoint and a routing balancer selecting them.
- Remove an empty 'servers' array entirely and fill the shorthand fields.
Example fix
// before
"outbounds": [{
"protocol": "socks",
"settings": {"servers": [{"address": "a.com", "port": 1080}, {"address": "b.com", "port": 1080}]}
}]
// after
"outbounds": [
{"tag": "socks-a", "protocol": "socks", "settings": {"servers": [{"address": "a.com", "port": 1080}]}},
{"tag": "socks-b", "protocol": "socks", "settings": {"servers": [{"address": "b.com", "port": 1080}]}}
],
"routing": {"balancers": [{"tag": "socks-bal", "selector": ["socks-a", "socks-b"]}]} Defensive patterns
Strategy: validation
Validate before calling
func validSocksOutbound(settings map[string]any) bool {
servers, ok := settings["servers"].([]any)
if !ok {
_, hasAddr := settings["address"]
return hasAddr
}
return len(servers) == 1
} Prevention
- Use separate SOCKS outbounds plus a balancer for multiple upstreams
- Migrate legacy multi-server arrays during V2Ray-to-Xray upgrades
When it happens
Trigger: A SOCKS outbound with settings.servers of length != 1 — an empty array, or two entries like [proxyA, proxyB] — and no top-level 'address' that would have been normalized to one entry.
Common situations: Legacy V2Ray 2.x/3.x configs with multiple SOCKS servers in one outbound; attempting failover by listing several upstream SOCKS proxies; omitting both the shorthand address and servers.
Related errors
- Shadowsocks settings: "servers" should have one and only one
- SOCKS servers: "users" should have one member at most. Multi
- Trojan settings: "servers" should have one and only one memb
- VLESS settings: "vnext" should have one and only one member.
- VMess settings: "vnext" should have one and only one member.
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/2c78fd3d0964b76f.
Report an issue: GitHub.