XTLS/Xray-core · error

failed to parse HTTP user

Error message

failed to parse HTTP user

What it means

Thrown when json.Unmarshal of a raw entry from httpSettings.servers[].users into protocol.User fails. Each users element is a JSON object whose fields (id/email/level in protocol.User terms) must deserialize cleanly; a type mismatch (e.g. level as a string) or malformed JSON surfaces here with the parse error as the base cause and AtError severity. Only hit on the servers[].users form, not the legacy top-level username form.

Source

Thrown at infra/conf/http.go:100

	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.Username
				account.Password = v.Password
			} else {
				if err := json.Unmarshal(rawUser, account); err != nil {
					return nil, errors.New("failed to parse HTTP account").Base(err).AtError()
				}
			}
			user.Account = serial.ToTypedMessage(account.Build())
			server.User = user
			break
		}
		config.Server = server
		break
	}

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Make each users element a valid JSON object with correctly typed fields (e.g. level as number)
  2. Pre-validate the outbound JSON with a linter or jq before feeding it to Xray
  3. Read the chained base error to find the exact JSON offset/field that failed

Example fix

// before
"users": [ { "user": "a", "level": "0" } ]
// after
"users": [ { "user": "a", "level": 0 } ]
Defensive patterns

Strategy: validation

Validate before calling

// Validate each users entry unmarshals into protocol.User cleanly
var probe protocol.User
if err := json.Unmarshal(rawUser, &probe); err != nil {
	return fmt.Errorf("users entry invalid: %w", err)
}

Try / catch

// Go: catch and enrich
if err := outboundConf.Build(); err != nil {
	if strings.Contains(err.Error(), "failed to parse HTTP user") {
		log.Printf("config file: users[%d] has wrong field types", i)
	}
	return err
}

Prevention

When it happens

Trigger: A users entry like {"level": "0"} (string where uint32 expected), an array element that is not an object, or invalid JSON syntax inside the users array.

Common situations: Hand-editing JSON and quoting numeric fields; config templating engines rendering booleans or nulls into user objects.

Understand the failure class

Related errors


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