{"record":{"id":"027599b48011addf","repo":"payloadcms/payload","slug":"username-is-required","errorCode":null,"errorMessage":"Username is required.","messagePattern":"Username is required\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/payload/src/auth/serverFunctions/login.ts","lineNumber":60,"sourceCode":"}: LoginArgs<TSlug>): Promise<LoginResult<TSlug>> {\n  const payload = await getPayload({ config, cron: true })\n\n  const authConfig = payload.collections[collection]?.config.auth\n\n  if (!authConfig) {\n    throw new Error(`No auth config found for collection: ${collection}`)\n  }\n\n  const loginWithUsername = authConfig.loginWithUsername ?? false\n\n  if (loginWithUsername) {\n    if (loginWithUsername.allowEmailLogin) {\n      if (!email && !username) {\n        throw new Error('Email or username is required.')\n      }\n    } else {\n      if (!username) {\n        throw new Error('Username is required.')\n      }\n    }\n  } else {\n    if (!email) {\n      throw new Error('Email is required.')\n    }\n  }\n\n  let loginData\n\n  if (loginWithUsername) {\n    loginData = username ? { password, username } : { email, password }\n  } else {\n    loginData = { email, password }\n  }\n\n  const collectionConfig = payload.collections[collection]!\n","sourceCodeStart":42,"sourceCodeEnd":78,"githubUrl":"https://github.com/payloadcms/payload/blob/00c58b35c0ed348ddc22daabf467b139727214fd/packages/payload/src/auth/serverFunctions/login.ts#L42-L78","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Pass a non-empty `username` in the `login` call.","Confirm the collection's `auth.loginWithUsername.allowEmailLogin` value matches what your form collects.","If the form collects email, set `allowEmailLogin: true` in the collection's auth config."],"exampleFix":"// before\nawait login({ collection: 'users', config, password, email: form.email, serverAdapter })\n// after\nawait login({ collection: 'users', config, password, username: form.username, serverAdapter })","handlingStrategy":"validation","validationCode":"function needsUsername(loginWithUsername) {\n  return !!loginWithUsername && !loginWithUsername.allowEmailLogin\n}\nfunction validateUsernameLogin(args) {\n  if (needsUsername(args.loginWithUsername) && !args.username?.trim()) {\n    return { ok: false, message: 'Username is required.' }\n  }\n  return { ok: true }\n}","typeGuard":"function hasUsername(args): args is { username: string } {\n  return typeof args?.username === 'string' && args.username.trim().length > 0\n}","tryCatchPattern":null,"preventionTips":["Match your login form fields to the collection's `loginWithUsername` config.","Trim and check for empty strings, not just undefined.","Rely on the `LoginArgs` discriminated union for compile-time enforcement."],"tags":["auth","login","validation","username"],"backgroundTag":null,"analyzedSha":"00c58b35c0ed348ddc22daabf467b139727214fd","analyzedAt":"2026-08-12T20:45:03.758Z","schemaVersion":2},"datasetVersion":"2026-08-12T23:17:12.415Z"}