XTLS/Xray-core · error

VLESS vnext: "users" should have one and only one member. Mu

Error message

VLESS vnext: "users" should have one and only one member. Multiple members in "users" should use multiple VLESS outbounds and routing balancer instead

What it means

Thrown by VLessOutboundConfig.Build() when the "users" array inside a vnext entry does not contain exactly one member. One VLESS outbound authenticates as exactly one user; multiple credentials must be split across multiple outbounds (optionally behind a routing balancer). An empty users array is rejected for the same reason.

Source

Thrown at infra/conf/vless.go:280

	config := new(outbound.Config)
	if c.Address != nil {
		c.Vnext = []*VLessOutboundVnext{
			{
				Address: c.Address,
				Port:    c.Port,
				Users:   []json.RawMessage{{}},
			},
		}
	}
	if len(c.Vnext) != 1 {
		return nil, errors.New(`VLESS settings: "vnext" should have one and only one member. Multiple endpoints in "vnext" should use multiple VLESS outbounds and routing balancer instead`)
	}
	for _, rec := range c.Vnext {
		if rec.Address == nil {
			return nil, errors.New(`VLESS vnext: "address" is not set`)
		}
		if len(rec.Users) != 1 {
			return nil, errors.New(`VLESS vnext: "users" should have one and only one member. Multiple members in "users" should use multiple VLESS outbounds and routing balancer instead`)
		}
		spec := &protocol.ServerEndpoint{
			Address: rec.Address.Build(),
			Port:    uint32(rec.Port),
		}
		for _, rawUser := range rec.Users {
			user := new(protocol.User)
			if c.Address != nil {
				user.Level = c.Level
				user.Email = c.Email
			} else {
				if err := json.Unmarshal(rawUser, user); err != nil {
					return nil, errors.New(`VLESS users: invalid user`).Base(err)
				}
			}
			account := new(vless.Account)
			if c.Address != nil {
				account.Id = c.Id

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Keep exactly one user object in outbound "users"
  2. If you need several identities/servers, use multiple outbounds plus a routing balancer
  3. Make sure the array is not empty — at least one {"id":"uuid","encryption":"none"} is required

Example fix

// before
"users": [ {"id":"uuid-a","encryption":"none"}, {"id":"uuid-b","encryption":"none"} ]
// after
"users": [ {"id":"uuid-a","encryption":"none"} ]
Defensive patterns

Strategy: validation

Validate before calling

func validateSingleUserPerVnext(cfg map[string]any) error {
	outbounds, _ := cfg["outbounds"].([]any)
	for _, ob := range outbounds {
		m, _ := ob.(map[string]any)
		if p, _ := m["protocol"].(string); p != "vless" { continue }
		settings, _ := m["settings"].(map[string]any)
		vnext, _ := settings["vnext"].([]any)
		for _, v := range vnext {
			ep, _ := v.(map[string]any)
			users, _ := ep["users"].([]any)
			if len(users) != 1 {
				return fmt.Errorf("outbound %v: vless vnext.users must have exactly 1 entry, got %d", m["tag"], len(users))
			}
		}
	}
	return nil
}

Type guard

func hasExactlyOneUser(ep map[string]any) bool {
	u, ok := ep["users"].([]any)
	return ok && len(u) == 1
}

Prevention

When it happens

Trigger: "vnext":[{"address":"a.com","port":443,"users":[]}] or users with two credential objects; commonly left over from editing an inbound clients list into an outbound.

Common situations: Copying the inbound "clients" array (which legitimately holds many users) into the outbound "users" field; deleting a user and leaving an empty array; misunderstanding that outbound users are credentials for dialing out, not for accepting.

Related errors


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