payloadcms/payload · error · Error

Username is required.

Error message

Username is required.

What it means

Thrown by the framework-agnostic `login` server function when the target auth collection has `auth.loginWithUsername` enabled but `loginWithUsername.allowEmailLogin` is falsy, and the caller did not supply a `username`. It is a pre-credential input guard: login is username-only for this collection, so Payload refuses to proceed without one.

Source

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

}: 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 }
  }

  const collectionConfig = payload.collections[collection]!

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Pass a non-empty `username` in the `login` call.
  2. Confirm the collection's `auth.loginWithUsername.allowEmailLogin` value matches what your form collects.
  3. If the form collects email, set `allowEmailLogin: true` in the collection's auth config.

Example fix

// before
await login({ collection: 'users', config, password, email: form.email, serverAdapter })
// after
await login({ collection: 'users', config, password, username: form.username, serverAdapter })
Defensive patterns

Strategy: validation

Validate before calling

function needsUsername(loginWithUsername) {
  return !!loginWithUsername && !loginWithUsername.allowEmailLogin
}
function validateUsernameLogin(args) {
  if (needsUsername(args.loginWithUsername) && !args.username?.trim()) {
    return { ok: false, message: 'Username is required.' }
  }
  return { ok: true }
}

Type guard

function hasUsername(args): args is { username: string } {
  return typeof args?.username === 'string' && args.username.trim().length > 0
}

Prevention

When it happens

Trigger: Calling `login({ collection, config, password, serverAdapter })` against a collection configured with `loginWithUsername: true` (or `{ allowEmailLogin: false }`) while omitting `username`, or passing `username: ''`. The `LoginArgs` discriminated union enforces this at compile time, but loose JS callers, form handlers, or adapters forwarding empty strings bypass it.

Common situations: A login form that always submits `email` but targets a username-only collection; the collection's auth config was switched from email to username-only without updating the form; an adapter that forwards `undefined`/empty for the username field.

Related errors


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