XTLS/Xray-core · error
VMess vnext: "users" should have one and only one member. Mu
Error message
VMess vnext: "users" should have one and only one member. Multiple members in "users" should use multiple VMess outbounds and routing balancer instead
What it means
Thrown by VMessOutboundConfig.Build() when vnext[].users does not contain exactly one member. Each VMess outbound authenticates as a single user; multiple credentials require separate outbounds (optionally behind a balancer), and an empty users array is likewise invalid.
Source
Thrown at infra/conf/vmess.go:141
func (c *VMessOutboundConfig) Build() (proto.Message, error) {
errors.PrintNonRemovalDeprecatedFeatureWarning("VMess (with no Forward Secrecy, etc.)", "VLESS Encryption")
config := new(outbound.Config)
if c.Address != nil {
c.Receivers = []*VMessOutboundTarget{
{
Address: c.Address,
Port: c.Port,
Users: []json.RawMessage{{}},
},
}
}
if len(c.Receivers) != 1 {
return nil, errors.New(`VMess settings: "vnext" should have one and only one member. Multiple endpoints in "vnext" should use multiple VMess outbounds and routing balancer instead`)
}
for _, rec := range c.Receivers {
if len(rec.Users) != 1 {
return nil, errors.New(`VMess vnext: "users" should have one and only one member. Multiple members in "users" should use multiple VMess outbounds and routing balancer instead`)
}
if rec.Address == nil {
return nil, errors.New(`VMess vnext: "address" is not set`)
}
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("invalid VMess user").Base(err)
}
}View on GitHub (pinned to 7d214f8b09)
Solutions
- Keep exactly one user object: {"id":"uuid","alterId":0,"security":"auto"}
- Split multiple identities into multiple outbounds and balance via routing
- Never leave "users" empty in an outbound vnext entry
Example fix
// before
"users": [ {"id":"uuid-a"}, {"id":"uuid-b"} ]
// after
"users": [ {"id":"uuid-a", "alterId": 0, "security": "auto"} ] Defensive patterns
Strategy: validation
Validate before calling
func validateVMessSingleUser(cfg map[string]any) error {
outbounds, _ := cfg["outbounds"].([]any)
for _, ob := range outbounds {
m, _ := ob.(map[string]any)
if p, _ := m["protocol"].(string); p != "vmess" { 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: vmess vnext.users must have exactly 1 entry, got %d", m["tag"], len(users))
}
}
}
return nil
} Type guard
func vmessOneUser(ep map[string]any) bool {
u, ok := ep["users"].([]any)
return ok && len(u) == 1
} Prevention
- Exactly one credential per outbound; never reuse inbound clients arrays as outbound users
- Assert len(users)==1 in config tooling before emitting
- Empty users arrays are invalid — always include the single {id, alterId, security} object
When it happens
Trigger: "vnext":[{"address":"a.com","port":443,"users":[]}]; users containing two credential objects; inbound-style clients arrays pasted into the outbound.
Common situations: Copying the server-side clients list into the outbound; removing a user while editing and leaving []; misunderstanding the one-identity-per-outbound rule.
Related errors
- VLESS vnext: "users" should have one and only one member. Mu
- VMess settings: "vnext" should have one and only one member.
- VMess vnext: "address" is not set
- unsupported domain strategy: {}
- invalid redirect address: {}
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/dcb12e9c3895a657.
Report an issue: GitHub.