XTLS/Xray-core · error

SOCKS servers: "users" should have one member at most. Multi

Error message

SOCKS servers: "users" should have one member at most. Multiple members in "users" should use multiple SOCKS outbounds and routing balancer instead

What it means

Xray-core rejects a SOCKS outbound (SocksClientConfig.Build, infra/conf/socks.go:105) whose server entry lists more than one member in the "users" array. Modern Xray allows at most one credential per SOCKS server entry; multi-credential setups must be modeled as multiple SOCKS outbounds combined with a routing balancer.

Source

Thrown at infra/conf/socks.go:105

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()
				}
			}
			account := new(SocksAccount)
			if v.Address != nil {
				account.Username = v.Username

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Keep exactly one user object per servers[] entry: {"servers":[{"address":"1.2.3.4","port":1080,"users":[{"user":"u","pass":"p"}]}]}
  2. If you need multiple credentials/endpoints, define one socks outbound per credential and load-balance them with a routing "balancers" entry over their tags
  3. Prefer the simpler flat form: settings:{"address":"1.2.3.4","port":1080,"user":"u","pass":"p"}, which supports one user implicitly

Example fix

// before
"settings": { "servers": [ { "address": "1.2.3.4", "port": 1080,
  "users": [ {"user":"a","pass":"x"}, {"user":"b","pass":"y"} ] } ] }
// after
"settings": { "servers": [ { "address": "1.2.3.4", "port": 1080,
  "users": [ {"user":"a","pass":"x"} ] } ] }
// (second credential -> second socks outbound + routing balancer)
Defensive patterns

Strategy: validation

Validate before calling

// JS: before writing config
const s = outbound.settings;
const servers = s.servers ?? [{address:s.address, port:s.port, users:s.user?[{user:s.user,pass:s.pass}]:[]}];
if (servers.length !== 1 || (servers[0].users?.length ?? 0) > 1) throw new Error('socks outbound: one server + at most one user; use multiple outbounds + balancer');

Try / catch

if (err.message.includes('users" should have one member')) { /* split into multiple outbounds and re-add balancer */ }

Prevention

When it happens

Trigger: An outbound with protocol "socks" whose "settings".servers[0].users contains 2 or more objects, e.g. {"servers":[{"address":"h","port":1,"users":[{...},{...}]}]}. Only fires in the new "servers" form; the legacy address/port/user/pass form cannot trigger it.

Common situations: Configs migrated from older Xray/V2Ray forks that permitted per-server user lists; copying a shared outbound template and appending users; scripts that generate one outbound per account but merge users into a single server.

Related errors


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