{"record":{"id":"01235450894d6e85","repo":"plandex-ai/plandex","slug":"user-already-exists-for-email-v","errorCode":null,"errorMessage":"user already exists for email: %v","messagePattern":"user already exists for email: (.+?)","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"app/server/db/user_helpers.go","lineNumber":149,"sourceCode":"\nfunc CreateUser(name, email string, tx *sqlx.Tx) (*User, error) {\n\temailSplit := strings.Split(email, \"@\")\n\tif len(emailSplit) != 2 {\n\t\treturn nil, fmt.Errorf(\"invalid email: %v\", email)\n\t}\n\tdomain := emailSplit[1]\n\n\tuser := User{\n\t\tName:   name,\n\t\tEmail:  email,\n\t\tDomain: domain,\n\t}\n\n\terr := tx.QueryRow(\"INSERT INTO users (name, email, domain) VALUES ($1, $2, $3) RETURNING id\", user.Name, user.Email, user.Domain).Scan(&user.Id)\n\n\tif err != nil {\n\t\tif IsNonUniqueErr(err) {\n\t\t\treturn nil, fmt.Errorf(\"user already exists for email: %v\", email)\n\t\t}\n\t\treturn nil, fmt.Errorf(\"error creating user: %v\", err)\n\t}\n\n\treturn &user, nil\n}\n\nfunc NumUsersWithRole(orgId, roleId string) (int, error) {\n\tvar count int\n\terr := Conn.Get(&count, \"SELECT COUNT(*) FROM orgs_users WHERE org_id = $1 AND org_role_id = $2\", orgId, roleId)\n\n\tif err != nil {\n\t\treturn 0, fmt.Errorf(\"error counting users with role: %v\", err)\n\t}\n\n\treturn count, nil\n}\n","sourceCodeStart":131,"sourceCodeEnd":167,"githubUrl":"https://github.com/plandex-ai/plandex/blob/e2d772072efadbe41d2946d97d79be55532dbab5/app/server/db/user_helpers.go#L131-L167","documentation":"CreateUser inserts into the users table with email as a unique key; when the DB rejects the insert with a unique-constraint violation, IsNonUniqueErr detects it and this error is returned instead of exposing the raw DB error.","triggerScenarios":"Calling CreateUser (via CreateAccount) with an email that already has a row in the users table, causing the unique index on email to reject the INSERT.","commonSituations":"Duplicate sign-up with the same email, user retrying a completed registration, two concurrent sign-ups racing on the same email, or reusing an email from an old account.","solutions":["Check for an existing user with GetUser/lookup by email before calling CreateUser","Catch this error and return a friendly 'account already exists, sign in instead' response (e.g. HTTP 409)","Route the user to the sign-in or password-reset flow","If accounts were partially created in the same tx, rely on the surrounding WithTx rollback and surface the conflict"],"exampleFix":"// before\nuser, err := db.CreateUser(name, email, tx)\n// after\nuser, err := db.CreateUser(name, email, tx)\nif err != nil && strings.HasPrefix(err.Error(), \"user already exists\") { return nil, ErrEmailTaken } // map to 409/sign-in prompt","handlingStrategy":"validation","validationCode":"var existing User\nerr := tx.Get(&existing, \"SELECT id FROM users WHERE email = $1\", email)\nif err == nil { return ErrEmailTaken } // check before insert\nif err != sql.ErrNoRows { return err }","typeGuard":"func isDuplicateUserErr(err error) bool { return strings.HasPrefix(err.Error(), \"user already exists for email\") }","tryCatchPattern":"user, err := db.CreateUser(name, email, tx)\nif err != nil {\n    if isDuplicateUserErr(err) { return nil, ErrEmailTaken } // map to 409 / sign-in redirect\n    return nil, err\n}","preventionTips":["Look up the email before inserting to give a friendly 409","Map duplicate-user errors to the sign-in flow, not a generic 500","Handle concurrent sign-ups: the unique index is the source of truth, the pre-check is UX only","Never expose raw DB errors to end users"],"tags":["go","database","uniqueness","duplicate"],"backgroundTag":"duplicate-key-violation","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"}