{"record":{"id":"e326713ade312426","repo":"plandex-ai/plandex","slug":"user-email-does-not-match","errorCode":null,"errorMessage":"User email does not match","messagePattern":"User email does not match","errorType":"http","errorClass":"http","httpStatus":400,"severity":"error","filePath":"app/server/handlers/sessions.go","lineNumber":68,"sourceCode":"\t\thasAccount = true\n\n\t\tuser, err := db.GetUser(req.UserId)\n\n\t\tif err != nil {\n\t\t\tlog.Printf(\"Error getting user: %v\\n\", err)\n\t\t\thttp.Error(w, \"Error getting user: \"+err.Error(), http.StatusInternalServerError)\n\t\t\treturn\n\t\t}\n\n\t\tif user == nil {\n\t\t\tlog.Printf(\"User not found for id: %v\\n\", req.UserId)\n\t\t\thttp.Error(w, \"User not found\", http.StatusNotFound)\n\t\t\treturn\n\t\t}\n\n\t\tif user.Email != req.Email {\n\t\t\tlog.Printf(\"User email does not match for id: %v\\n\", req.UserId)\n\t\t\thttp.Error(w, \"User email does not match\", http.StatusBadRequest)\n\t\t\treturn\n\t\t}\n\t}\n\n\tif req.RequireUser && !hasAccount {\n\t\tlog.Printf(\"User not found for email: %v\\n\", req.Email)\n\t\thttp.Error(w, \"User not found\", http.StatusNotFound)\n\t\treturn\n\t} else if req.RequireNoUser && hasAccount {\n\t\tlog.Printf(\"User already exists for email: %v\\n\", req.Email)\n\t\thttp.Error(w, \"User already exists\", http.StatusConflict)\n\t\treturn\n\t}\n\n\tvar res shared.CreateEmailVerificationResponse\n\n\tif !(os.Getenv(\"GOENV\") == \"development\" && os.Getenv(\"LOCAL_MODE\") == \"1\") {\n\t\t// create pin - 6 alphanumeric characters","sourceCodeStart":50,"sourceCodeEnd":86,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/handlers/sessions.go#L50-L86","documentation":"CreateEmailVerificationHandler returns HTTP 400 'User email does not match' when a UserId is supplied and the email stored for that user does not equal the request Email (after lowercasing). The handler requires the (userId, email) pair to be consistent before issuing a verification pin, protecting against sending pins to an address that does not own the account.","triggerScenarios":"POSTing CreateEmailVerificationRequest with a valid UserId but an Email field different from the user's registered email; omitting the Email field entirely (empty string never matches); sending mixed-case email that lowercases to something different from the stored address (rare if stored normalized).","commonSituations":"Client uses a different personal email for sign-in attempt than the one registered (user forgot which email they signed up with); client sends userId but leaves email blank; a bug where the client fetches one user's ID and another's email; after an email change, the client still caches the old address.","solutions":["Log the user out / clear stored credentials and have them re-enter the exact email registered to the account.","Call an account-info endpoint (or query the DB) to confirm the email associated with the UserId and use that email in the request.","Normalize the email client-side (strings.ToLower(strings.TrimSpace(email))) before sending so casing/whitespace never mismatches.","If the user wants to change to the new email, use the proper email-change flow (which verifies the new address) rather than CreateEmailVerification with a mismatched pair.","Remove the UserId from the request if the goal is just an account-existence check by email; then the handler looks up by email only."],"exampleFix":"// before\nreq := shared.CreateEmailVerificationRequest{ UserId: userID, Email: typedEmail }\n// after\nreq := shared.CreateEmailVerificationRequest{\n    UserId: userID,\n    Email:  strings.ToLower(strings.TrimSpace(typedEmail)), // must equal user.Email\n}\nif storedEmailForUser(userID) != req.Email {\n    // route to email-change flow instead\n}","handlingStrategy":"validation","validationCode":"// normalize and confirm the email matches what the server has for this user\nemail := strings.ToLower(strings.TrimSpace(inputEmail))\nif req.UserId != \"\" && email != storedEmailForUser(req.UserId) {\n    // mismatch: use the stored email or route to the email-change flow\n    req.Email = storedEmailForUser(req.UserId)\n}","typeGuard":null,"tryCatchPattern":"resp, err := http.Post(url, \"application/json\", body)\nif err != nil { return err }\nif resp.StatusCode == http.StatusBadRequest {\n    // email/userId pair inconsistent: clear stored pair and prompt user to re-enter email\n    clearStoredEmail()\n    return promptUserForEmail()\n}","preventionTips":["Always lowercase and trim emails client-side before sending (the server lowercases too).","Never send UserId with an email other than the one bound to that account.","After an email-change flow completes, update the client's cached email immediately.","Prompt users to confirm which email they registered with instead of silently guessing."],"tags":["http-400","bad-request","email-mismatch","email-verification","auth"],"backgroundTag":"email-mismatch","analyzedSha":"e2d772072efadbe41d2946d97d79be55532dbab5","analyzedAt":"2026-09-05T20:56:53.631Z","contentChangedAt":"2026-09-05T20:56:53.631Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}