XTLS/Xray-core · error
HTTP servers: "users" should have one member at most. Multip
Error message
HTTP servers: "users" should have one member at most. Multiple members in "users" should use multiple HTTP outbounds and routing balancer instead
What it means
Thrown by the HTTP outbound builder when a server entry's users array has more than one member. Each HTTP outbound authenticates with at most one credential pair; multiple credentials require multiple HTTP outbounds and a routing balancer. An empty users array is allowed (no auth).
Source
Thrown at infra/conf/http.go:87
func (v *HTTPClientConfig) Build() (proto.Message, error) {
config := new(http.ClientConfig)
if v.Address != nil {
v.Servers = []*HTTPRemoteConfig{
{
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(`HTTP settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple HTTP outbounds and routing balancer instead`)
}
for _, serverConfig := range v.Servers {
if len(serverConfig.Users) > 1 {
return nil, errors.New(`HTTP servers: "users" should have one member at most. Multiple members in "users" should use multiple HTTP 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 HTTP user").Base(err).AtError()
}
}
account := new(HTTPAccount)
if v.Address != nil {
account.Username = v.UsernameView on GitHub (pinned to 7d214f8b09)
Solutions
- Keep users to zero or one entry per server
- Move each credential to its own HTTP outbound and use a routing balancer to distribute traffic
Example fix
// before
"users": [ {"user":"a","pass":"x"}, {"user":"b","pass":"y"} ]
// after
"users": [ {"user":"a","pass":"x"} ] // second credential in a separate HTTP outbound Defensive patterns
Strategy: validation
Validate before calling
for _, s := range httpSettings.Servers {
if len(s.Users) > 1 {
return fmt.Errorf("server %v has %d users; max is 1", s.Address, len(s.Users))
}
} Prevention
- Encode at most one credential per HTTP outbound
- Lint generated configs for users arrays longer than 1
When it happens
Trigger: Putting two or more user objects inside httpSettings.servers[0].users; mixing the legacy username/password fields with an extra users entry is safe (legacy path synthesizes exactly one user), but explicit users arrays with 2+ entries fail.
Common situations: Users trying to encode failover credentials for several upstream proxies in one outbound; generated configs that emit a users list unconditionally.
Related errors
- HTTP settings: "servers" should have one and only one member
- failed to parse HTTP account
- empty HTTP header value: + key
- bridge tag is empty
- bridge domain is empty
AI-assisted analysis of XTLS/Xray-core@7d214f8b09 (2026-08-15).
Data as JSON: /api/errors/52c0231ad9727a01.
Report an issue: GitHub.