payloadcms/payload · error · ValidationError

A user with the given email is already registered.

Error message

A user with the given email is already registered.

What it means

Same `registerLocalStrategy` check, but fires when `canLoginWithUsername` is false (standard email auth). Throws a `ValidationError` with the localized `userEmailAlreadyRegistered` message on the `email` path when an existing user matches the email.

Source

Thrown at packages/payload/src/auth/strategies/local/register.ts:68

      whereConstraint.or?.push({
        username: {
          equals: doc.username,
        },
      })
    }
  }

  const existingUser = await payload.find({
    collection: collection.slug,
    depth: 0,
    limit: 1,
    pagination: false,
    req,
    where: whereConstraint,
  })

  if (existingUser.docs.length > 0) {
    throw new ValidationError({
      collection: collection.slug,
      errors: [
        canLoginWithUsername
          ? {
              message: req.t('error:usernameAlreadyRegistered'),
              path: 'username',
            }
          : { message: req.t('error:userEmailAlreadyRegistered'), path: 'email' },
      ],
    })
  }

  const { hash, salt } = await generatePasswordSaltHash({ collection, password, req })

  const sanitizedDoc = { ...doc }
  if (sanitizedDoc.password) {
    delete sanitizedDoc.password
  }

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Use a unique email.
  2. Pre-check email existence with `payload.find`.
  3. Add a DB unique index on the email column.

Example fix

// before
await payload.create({ collection: 'users', data: { email: 'a@b.com', password, ... } })
// after
const exists = await payload.find({ collection: 'users', limit: 1, pagination: false, where: { email: { equals: 'a@b.com' } } })
if (exists.docs.length) throw new Error('email registered')
await payload.create({ collection: 'users', data: { email: 'a@b.com', password, ... } })
Defensive patterns

Strategy: try-catch

Validate before calling

async function isEmailAvailable(payload, slug, email) {
  const res = await payload.find({ collection: slug, limit: 1, pagination: false, where: { email: { equals: email } } })
  return res.docs.length === 0
}

Type guard

function isValidationError(e): e is ValidationError {
  return e?.name === 'ValidationError' && Array.isArray(e?.data?.errors)
}

Try / catch

try {
  await payload.create({ collection: 'users', data })
} catch (e) {
  if (isValidationError(e) && e.data.errors.some(x => x.path === 'email')) {
    setFieldError('email', 'already registered')
  } else throw e
}

Prevention

When it happens

Trigger: Registering with an email that already exists in an email-login auth collection.

Common situations: Duplicate signup with the same email; re-running seeders; email column lacking a DB-level unique constraint.

Related errors


AI-assisted analysis of payloadcms/payload@00c58b35c0 (2026-08-12). Data as JSON: /api/errors/33ca3032a3bb670d. Report an issue: GitHub.