XTLS/Xray-core · error

VLESS users: invalid user

Error message

VLESS users: invalid user

What it means

Thrown inside the per-client loop of a VLESS inbound when a raw user JSON object fails to unmarshal into protocol.User (the generic user record with email/level). This almost always means the clients entry is not a JSON object with compatible fields — wrong type for email/level, or the entry itself is a string/array.

Source

Thrown at infra/conf/vless.go:59

// Build implements Buildable
func (c *VLessInboundConfig) Build() (proto.Message, error) {
	config := new(inbound.Config)

	if c.Clients != nil {
		c.Users = c.Clients
	}
	config.Users = make([]*protocol.User, len(c.Users))
	switch c.Flow {
	case vless.XRV, "":
	default:
		return nil, errors.New(`VLESS "settings.flow" doesn't support "` + c.Flow + `" in this version`)
	}
	processClient := func(idx int) error {
		rawUser := c.Users[idx]
		user := new(protocol.User)
		if err := json.Unmarshal(rawUser, user); err != nil {
			return errors.New(`VLESS users: invalid user`).Base(err)
		}
		account := new(vless.Account)
		if err := json.Unmarshal(rawUser, account); err != nil {
			return errors.New(`VLESS users: invalid user`).Base(err)
		}

		u, err := uuid.ParseString(account.Id)
		if err != nil {
			return err
		}
		account.Id = u.String()

		switch account.Flow {
		case "":
			account.Flow = c.Flow
		case vless.XRV:
		default:
			return errors.New(`VLESS users: "flow" doesn't support "` + account.Flow + `" in this version`)

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Make each clients entry an object: { "id": "<uuid>", "email": "optional", "level": 0 }
  2. Keep level as a JSON number and email as a string
  3. Read the wrapped base error — it names the exact offending field

Example fix

// before
"clients": [ "8c1f4b1a-..." ]
// after
"clients": [ { "id": "8c1f4b1a-...", "level": 0 } ]
Defensive patterns

Strategy: validation

Validate before calling

// each clients entry must be an object with string email and numeric level (both optional)
for _, c := range clients {
    if !gjson.Valid(c.Raw) || c.Type != gjson.JSON {
        return errors.New("each vless client must be a JSON object")
    }
    if e := gjson.Get(c.Raw, "email"); e.Exists() && e.Type != gjson.String {
        return errors.New("client email must be a string")
    }
    if l := gjson.Get(c.Raw, "level"); l.Exists() && l.Type != gjson.Number {
        return errors.New("client level must be a number")
    }
}

Prevention

When it happens

Trigger: A "clients" entry like { "id": "...", "level": "high" } (level must be a number) or "clients": ["uuid-string"] (bare string instead of object). The error is wrapped as 'VLESS users: invalid user' with the underlying JSON error attached.

Common situations: Pasting a bare UUID list instead of client objects, or quoting numeric fields during YAML→JSON conversion.

Related errors


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