payloadcms/payload · error · Error

Email or username is required.

Error message

Email or username is required.

What it means

Thrown in the server-function `login` when the collection uses `loginWithUsername` with `allowEmailLogin: true` and neither `email` nor `username` is supplied. Payload cannot identify the account with zero identifiers. Plain `Error` (no HTTP status).

Source

Thrown at packages/payload/src/auth/serverFunctions/login.ts:56

  email,
  password,
  serverAdapter,
  username,
}: LoginArgs<TSlug>): Promise<LoginResult<TSlug>> {
  const payload = await getPayload({ config, cron: true })

  const authConfig = payload.collections[collection]?.config.auth

  if (!authConfig) {
    throw new Error(`No auth config found for collection: ${collection}`)
  }

  const loginWithUsername = authConfig.loginWithUsername ?? false

  if (loginWithUsername) {
    if (loginWithUsername.allowEmailLogin) {
      if (!email && !username) {
        throw new Error('Email or username is required.')
      }
    } else {
      if (!username) {
        throw new Error('Username is required.')
      }
    }
  } else {
    if (!email) {
      throw new Error('Email is required.')
    }
  }

  let loginData

  if (loginWithUsername) {
    loginData = username ? { password, username } : { email, password }
  } else {
    loginData = { email, password }

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Pass exactly one identifier: `login({ collection, password, email, serverAdapter })` or `login({ collection, password, username, serverAdapter })`.
  2. Validate that at least one of email/username is non-empty before calling.
  3. Respect the `LoginArgs` union type (`{ email } | { username }`) so TypeScript enforces the either/or.

Example fix

// before
await login({ collection, password, serverAdapter })
// after
await login({ collection, password, email: identifier, serverAdapter })
Defensive patterns

Strategy: validation

Validate before calling

// Ensure exactly one identifier is provided
if (!email && !username) {
  throw new Error('Email or username is required')
}
await login({
  collection,
  config,
  password,
  ...(email ? { email } : { username }),
  serverAdapter,
})

Type guard

function hasLoginIdentifier(args: { email?: string; username?: string }): boolean {
  return !!args.email || !!args.username
}

Try / catch

// Plain Error (not APIError) — validate before calling instead
if (!email && !username) {
  // prompt the user for an identifier
} else {
  await login({ collection, config, password, ...(email ? { email } : { username }), serverAdapter })
}

Prevention

When it happens

Trigger: Calling `login({ collection, password, serverAdapter })` without `email` or `username`; both fields are empty strings; the adapter's caller destructured only `password`. With `allowEmailLogin`, exactly one of email/username is required.

Common situations: A login form that conditionally renders email/username but submits when both are blank; the union type `LoginArgs` is bypassed by a `as any` cast; the frontend forgot to include the identifier field in the POST body that the adapter reads.

Related errors


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