XTLS/Xray-core · error

Shadowsocks 2022 accept no multi servers

Error message

Shadowsocks 2022 accept no multi servers

What it means

In the legacy (non-2022) Shadowsocks outbound path, the builder iterates over all server entries; Shadowsocks-2022 ciphers are only allowed in the single-server fast path. Encountering a 2022 method while iterating multiple servers triggers this error — 2022 does not support the legacy multi-server array.

Source

Thrown at infra/conf/shadowsocks.go:242

				return nil, errors.New("Invalid Shadowsocks port.")
			}
			if server.Password == "" {
				return nil, errors.New("Shadowsocks password is not specified.")
			}

			config := new(shadowsocks_2022.ClientConfig)
			config.Address = server.Address.Build()
			config.Port = uint32(server.Port)
			config.Method = server.Cipher
			config.Key = server.Password
			return config, nil
		}
	}

	config := new(shadowsocks.ClientConfig)
	for _, server := range v.Servers {
		if C.Contains(shadowaead_2022.List, server.Cipher) {
			return nil, errors.New("Shadowsocks 2022 accept no multi servers")
		}
		if server.Address == nil {
			return nil, errors.New("Shadowsocks server address is not set.")
		}
		if server.Port == 0 {
			return nil, errors.New("Invalid Shadowsocks port.")
		}
		if server.Password == "" {
			return nil, errors.New("Shadowsocks password is not specified.")
		}
		account := &shadowsocks.Account{
			Password: server.Password,
		}
		account.CipherType = cipherFromString(server.Cipher)
		if account.CipherType == shadowsocks.CipherType_UNKNOWN {
			return nil, errors.New("unknown cipher method: ", server.Cipher)
		}

View on GitHub (pinned to 7d214f8b09)

Solutions

  1. Split 2022 servers into their own dedicated outbound with exactly one server.
  2. Keep only classic AEAD ciphers in any multi-server legacy outbound.
  3. Prefer separate outbounds + routing balancer for multiple endpoints of any type.

Example fix

// before
"servers": [
  {"address": "a.com", "port": 443, "method": "aes-128-gcm", "password": "..."},
  {"address": "b.com", "port": 443, "method": "2022-blake3-aes-256-gcm", "password": "..."}
]

// after: separate outbounds per endpoint, each with one server
Defensive patterns

Strategy: validation

Validate before calling

var ss2022Prefixes = []string{"2022-blake3-"}

func is2022Cipher(m string) bool {
    for _, p := range ss2022Prefixes {
        if strings.HasPrefix(m, p) {
            return true
        }
    }
    return false
}

func validServers(servers []Server) bool {
    if len(servers) > 1 {
        for _, s := range servers {
            if is2022Cipher(s.Cipher) {
                return false
            }
        }
    }
    return true
}

Prevention

When it happens

Trigger: Reaching the legacy loop with a 2022 cipher in any servers entry — practically, a 2022 server entry combined with entries that are not caught by the earlier single-2022 branch, e.g. the first server is classic and a later one uses a 2022 method.

Common situations: Mixing 2022 and classic servers in one outbound; adding a 2022 endpoint to an old multi-server list left over from V2Ray configs.

Related errors


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