plandex-ai/plandex · warning
user already exists for email: %v
Error message
user already exists for email: %v
What it means
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.
Source
Thrown at app/server/db/user_helpers.go:149
func CreateUser(name, email string, tx *sqlx.Tx) (*User, error) {
emailSplit := strings.Split(email, "@")
if len(emailSplit) != 2 {
return nil, fmt.Errorf("invalid email: %v", email)
}
domain := emailSplit[1]
user := User{
Name: name,
Email: email,
Domain: domain,
}
err := tx.QueryRow("INSERT INTO users (name, email, domain) VALUES ($1, $2, $3) RETURNING id", user.Name, user.Email, user.Domain).Scan(&user.Id)
if err != nil {
if IsNonUniqueErr(err) {
return nil, fmt.Errorf("user already exists for email: %v", email)
}
return nil, fmt.Errorf("error creating user: %v", err)
}
return &user, nil
}
func NumUsersWithRole(orgId, roleId string) (int, error) {
var count int
err := Conn.Get(&count, "SELECT COUNT(*) FROM orgs_users WHERE org_id = $1 AND org_role_id = $2", orgId, roleId)
if err != nil {
return 0, fmt.Errorf("error counting users with role: %v", err)
}
return count, nil
}
View on GitHub (pinned to e2d772072e)
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
Example fix
// before
user, err := db.CreateUser(name, email, tx)
// after
user, err := db.CreateUser(name, email, tx)
if err != nil && strings.HasPrefix(err.Error(), "user already exists") { return nil, ErrEmailTaken } // map to 409/sign-in prompt Defensive patterns
Strategy: validation
Validate before calling
var existing User
err := tx.Get(&existing, "SELECT id FROM users WHERE email = $1", email)
if err == nil { return ErrEmailTaken } // check before insert
if err != sql.ErrNoRows { return err } Type guard
func isDuplicateUserErr(err error) bool { return strings.HasPrefix(err.Error(), "user already exists for email") } Try / catch
user, err := db.CreateUser(name, email, tx)
if err != nil {
if isDuplicateUserErr(err) { return nil, ErrEmailTaken } // map to 409 / sign-in redirect
return nil, err
} Prevention
- 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
When it happens
Trigger: 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.
Common situations: 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.
Related errors
- error invalidating conflicted results: %v
- error adding plan context tokens: %v
- error adding org member: %v
- error listing org roles: %v
- error adding org user: %v
AI-assisted analysis of plandex-ai/plandex@e2d772072e (2026-09-05).
Data as JSON: /api/errors/01235450894d6e85.
Report an issue: GitHub.