{"record":{"id":"b9ef0c198776455d","repo":"XTLS/Xray-core","slug":"user-email-not-found","errorCode":null,"errorMessage":"User ${email} not found.","messagePattern":"User (.+?) not found\\.","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"proxy/shadowsocks/validator.go","lineNumber":66,"sourceCode":"func (v *Validator) Del(email string) error {\n\tif email == \"\" {\n\t\treturn errors.New(\"Email must not be empty.\")\n\t}\n\n\tv.Lock()\n\tdefer v.Unlock()\n\n\temail = strings.ToLower(email)\n\tidx := -1\n\tfor i, u := range v.users {\n\t\tif strings.EqualFold(u.Email, email) {\n\t\t\tidx = i\n\t\t\tbreak\n\t\t}\n\t}\n\n\tif idx == -1 {\n\t\treturn errors.New(\"User \", email, \" not found.\")\n\t}\n\tulen := len(v.users)\n\n\tv.users[idx] = v.users[ulen-1]\n\tv.users[ulen-1] = nil\n\tv.users = v.users[:ulen-1]\n\n\treturn nil\n}\n\n// GetByEmail Get a Shadowsocks user with a non-empty Email.\nfunc (v *Validator) GetByEmail(email string) *protocol.MemoryUser {\n\tif email == \"\" {\n\t\treturn nil\n\t}\n\n\tv.Lock()\n\tdefer v.Unlock()","sourceCodeStart":48,"sourceCodeEnd":84,"githubUrl":"https://github.com/XTLS/Xray-core/blob/7d214f8b094f75322fa3990f8aadad1c912f24f5/proxy/shadowsocks/validator.go#L48-L84","documentation":"Lookup failure in Validator.Del: no user in the validator matches the given email (case-insensitive comparison via strings.EqualFold after lowercasing the input). The user list was scanned, idx stayed -1, and the delete is rejected without mutating state. Commonly a stale UI list, typo, or an email that belongs to a different inbound.","triggerScenarios":"Calling Validator.Del with an email that is not registered in this validator: user already removed, email from another inbound's user list, whitespace/copy artifacts, or user added to a different handler instance.","commonSituations":"Panel showing a cached user list after another admin removed the user; API retry after a successful delete; emails differing by dots/plus-addressing or unicode; automation scripts with hardcoded emails that drift.","solutions":["List current users (panel or logs) and confirm the exact email string, including case and whitespace.","If the user was already deleted, treat the error as idempotent success in automation code.","Scope the delete to the correct inbound tag/handler — validators are per-inbound."],"exampleFix":"// before\nvalidator.Del(\"alice@example.com \") // trailing space -> not found\n// after\nvalidator.Del(strings.TrimSpace(\"alice@example.com \"))","handlingStrategy":"try-catch","validationCode":"// existence pre-check (same comparison as Validator)\nfunc userExists(v *Validator, email string) bool {\n  return v.GetByEmail(strings.ToLower(strings.TrimSpace(email))) != nil\n}","typeGuard":null,"tryCatchPattern":"if err := v.Del(email); err != nil {\n  if strings.Contains(err.Error(), \"not found\") {\n    return nil // idempotent delete\n  }\n  return err\n}","preventionTips":["Trim and lowercase emails before calling Del.","Make deletes idempotent in automation scripts.","Refresh the user list from the API before issuing deletes."],"tags":["shadowsocks","users","lookup","api","not-found"],"backgroundTag":null,"analyzedSha":"7d214f8b094f75322fa3990f8aadad1c912f24f5","analyzedAt":"2026-08-15T14:26:24.325Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}