XTLS/Xray-core · error

failed to parse Socks user

Error message

failed to parse Socks user

What it means

While building a SOCKS outbound, Xray unmarshals each raw JSON user object into protocol.User (infra/conf/socks.go:117-118). Any JSON shape that cannot decode into that protobuf-generated struct aborts config load with "failed to parse Socks user" wrapping the JSON error. The user object must be a flat object with valid field types (e.g. "level": number, "email": string).

Source

Thrown at infra/conf/socks.go:118

	if len(v.Servers) != 1 {
		return nil, errors.New(`SOCKS settings: "servers" should have one and only one member. Multiple endpoints in "servers" should use multiple SOCKS outbounds and routing balancer instead`)
	}
	for _, serverConfig := range v.Servers {
		if len(serverConfig.Users) > 1 {
			return nil, errors.New(`SOCKS servers: "users" should have one member at most. Multiple members in "users" should use multiple SOCKS 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 Socks user").Base(err).AtError()
				}
			}
			account := new(SocksAccount)
			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 socks 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[i] a JSON object: {"user":"name","pass":"pw","level":0,"email":"opt"}
  2. Ensure level is an unquoted integer and email is a string; remove non-schema keys with wrong types
  3. Validate the whole config parses as strict JSON before feeding Xray (xray run -test or a JSON linter)

Example fix

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

Strategy: validation

Validate before calling

for (const u of server.users ?? []) {
  if (typeof u !== 'object' || u === null || Array.isArray(u)) throw new Error('user entry must be an object');
  if ('level' in u && !Number.isInteger(u.level)) throw new Error('level must be an integer');
  if ('email' in u && typeof u.email !== 'string') throw new Error('email must be a string');
}

Type guard

const isUserObject = (u: unknown): u is {user?:string; pass?:string; level?:number; email?:string} =>
  typeof u === 'object' && u !== null && !Array.isArray(u) &&
  (!('level' in u) || typeof (u as any).level === 'number') &&
  (!('email' in u) || typeof (u as any).email === 'string');

Try / catch

catch (e) { if (e.message.includes('failed to parse Socks user')) { /* surface e.cause: json field/type mismatch in users[] entry */ } }

Prevention

When it happens

Trigger: Only in the "servers" form (legacy address/port form skips unmarshal). A users[i] entry that is not an object (a string, number, array), or that contains type mismatches such as "level":"3" (string instead of number) or "email":123. Unknown keys are ignored; wrong value types are not.

Common situations: Quoting numbers in generated configs; pasting user entries copied from inbound "accounts" sections whose schema differs; trailing commas or comments breaking JSON; passing an array of strings instead of objects.

Understand the failure class

Related errors


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