{"record":{"id":"8261a37b3a4c1177","repo":"XTLS/Xray-core","slug":"shadowsocks-2022-relay-users-must-have-empty-me","errorCode":null,"errorMessage":"shadowsocks 2022 (relay): users must have empty method","messagePattern":"shadowsocks 2022 \\(relay\\): users must have empty method","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"infra/conf/shadowsocks.go","lineNumber":164,"sourceCode":"\t\t\t\tEmail:   user.Email,\n\t\t\t\tLevel:   uint32(user.Level),\n\t\t\t\tAccount: serial.ToTypedMessage(account),\n\t\t\t}\n\t\t\treturn nil\n\t\t}\n\t\tif err := task.ParallelForN(len(v.Users), processUser); err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\treturn config, nil\n\t}\n\n\tconfig := new(shadowsocks_2022.RelayServerConfig)\n\tconfig.Method = v.Cipher\n\tconfig.Key = v.Password\n\tconfig.Network = v.NetworkList.Build()\n\tfor _, user := range v.Users {\n\t\tif user.Cipher != \"\" {\n\t\t\treturn nil, errors.New(\"shadowsocks 2022 (relay): users must have empty method\")\n\t\t}\n\t\tif user.Address == nil {\n\t\t\treturn nil, errors.New(\"shadowsocks 2022 (relay): all users must have relay address\")\n\t\t}\n\t\tconfig.Destinations = append(config.Destinations, &shadowsocks_2022.RelayDestination{\n\t\t\tKey:     user.Password,\n\t\t\tEmail:   user.Email,\n\t\t\tAddress: user.Address.Build(),\n\t\t\tPort:    uint32(user.Port),\n\t\t})\n\t}\n\treturn config, nil\n}\n\ntype ShadowsocksServerTarget struct {\n\tAddress  *Address `json:\"address\"`\n\tPort     uint16   `json:\"port\"`\n\tLevel    byte     `json:\"level\"`","sourceCodeStart":146,"sourceCodeEnd":182,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/infra/conf/shadowsocks.go#L146-L182","documentation":"In Shadowsocks-2022 relay mode (users have addresses), relay destinations share the server-level method for key derivation, so individual user cipher entries are rejected. This is the relay counterpart of the multi-user 'empty method' rule.","triggerScenarios":"A 2022 relay inbound where any destination user in 'users' carries a non-empty 'cipher' field.","commonSituations":"Copying multi-user configs into relay setups and leaving per-user methods; template generators that populate all fields.","solutions":["Delete the per-user 'cipher' field from every relay destination entry.","Keep only 'password', 'address', 'port', 'email', 'level' on each user; the method lives solely on the server."],"exampleFix":"// before\n\"users\": [{\"cipher\": \"2022-blake3-aes-256-gcm\", \"address\": \"next-hop\", \"port\": 8388, \"password\": \"...\"}]\n\n// after\n\"users\": [{\"address\": \"next-hop\", \"port\": 8388, \"password\": \"...\"}]","handlingStrategy":"validation","validationCode":"func validRelayUsers(users []User) bool {\n    for _, u := range users {\n        if u.Cipher != \"\" {\n            return false\n        }\n    }\n    return true\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Relay destinations carry address+port+password only"],"tags":["shadowsocks-2022","relay","config"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}