{"record":{"id":"ba1572046bfe643f","repo":"XTLS/Xray-core","slug":"email-must-not-be-empty-ba1572","errorCode":null,"errorMessage":"Email must not be empty.","messagePattern":"Email must not be empty\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/trojan/validator.go","lineNumber":33,"sourceCode":"\tusers sync.Map\n}\n\n// Add a trojan user, Email must be empty or unique.\nfunc (v *Validator) Add(u *protocol.MemoryUser) error {\n\tif u.Email != \"\" {\n\t\t_, loaded := v.email.LoadOrStore(strings.ToLower(u.Email), u)\n\t\tif loaded {\n\t\t\treturn errors.New(\"User \", u.Email, \" already exists.\")\n\t\t}\n\t}\n\tv.users.Store(hexString(u.Account.(*MemoryAccount).Key), u)\n\treturn nil\n}\n\n// Del a trojan user with a non-empty Email.\nfunc (v *Validator) Del(e string) error {\n\tif e == \"\" {\n\t\treturn errors.New(\"Email must not be empty.\")\n\t}\n\tle := strings.ToLower(e)\n\tu, _ := v.email.Load(le)\n\tif u == nil {\n\t\treturn errors.New(\"User \", e, \" not found.\")\n\t}\n\tv.email.Delete(le)\n\tv.users.Delete(hexString(u.(*protocol.MemoryUser).Account.(*MemoryAccount).Key))\n\treturn nil\n}\n\n// Get a trojan user with hashed key, nil if user doesn't exist.\nfunc (v *Validator) Get(hash string) *protocol.MemoryUser {\n\tu, _ := v.users.Load(hash)\n\tif u != nil {\n\t\treturn u.(*protocol.MemoryUser)\n\t}\n\treturn nil","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/trojan/validator.go#L15-L51","documentation":"Validator.Del was called with an empty email string. Deletion looks users up by email key, so an empty key cannot identify any user and is rejected outright rather than silently doing nothing.","triggerScenarios":"Management API 'remove trojan user' style handlers invoked with an omitted/blank email field; config tooling that maps a missing email to \"\" and still calls Del.","commonSituations":"Automation scripts deleting by password instead of email; JSON payload with a typo'd field name so email decodes as empty.","solutions":["Pass the exact non-empty email the user was added with (case-insensitive on lookup)","Validate the email field is present before calling the remove API/handler","If the target user has no email, add one first or remove/rebuild the inbound"],"exampleFix":"// before\nremoveUser(inboundTag, \"\")\n// after\nremoveUser(inboundTag, \"user@x\")","handlingStrategy":"validation","validationCode":"// guard the management call\nfunc delUser(v *Validator, email string) error {\n    if strings.TrimSpace(email) == \"\" {\n        return errors.New(\"refusing to delete: email is empty\")\n    }\n    return v.Del(email)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Validate required fields at the API edge before they reach Validator.Del","Use typed request structs so a missing email fails decoding instead of silently passing \"\"","Reject blank emails in provisioning tooling early, with a clear message"],"tags":["trojan","users","api-misuse"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}