payloadcms/payload · error · APIError

Missing required data.

Error message

Missing required data.

What it means

Thrown in `resetPassword` when `data` lacks either `token` or `password` (checked via `Object.prototype.hasOwnProperty.call`). Both are required to look up the reset request and set the new credential. `APIError` with HTTP 400 (BAD_REQUEST).

Source

Thrown at packages/payload/src/auth/operations/resetPassword.ts:55

  args: Arguments,
): Promise<Result> => {
  const {
    collection: { config: collectionConfig },
    data,
    depth,
    overrideAccess,
    req: {
      payload: { secret },
      payload,
    },
    req,
  } = args

  if (
    !Object.prototype.hasOwnProperty.call(data, 'token') ||
    !Object.prototype.hasOwnProperty.call(data, 'password')
  ) {
    throw new APIError('Missing required data.', httpStatus.BAD_REQUEST)
  }

  if (collectionConfig.auth.disableLocalStrategy) {
    throw new Forbidden(req.t)
  }

  let sid: string | undefined
  let user: null | User = null

  try {
    const shouldCommit = await initTransaction(req)

    args = await buildBeforeOperation({
      args,
      collection: args.collection.config,
      operation: 'resetPassword',
      overrideAccess,
    })

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Send both fields: `data: { token, password }` where `token` is the value from the reset email URL.
  2. Validate client-side that both are non-empty before posting.
  3. If using the Local API, build the full `data` object including the token from the email link.
  4. Ensure form serialization includes the hidden token input.

Example fix

// before
await payload.resetPassword({ collection: 'users', data: { password }, req })
// after
await payload.resetPassword({ collection: 'users', data: { token, password }, req })
Defensive patterns

Strategy: validation

Validate before calling

// Validate both fields are present before resetting
if (!data.token || !data.password) {
  throw new Error('Both token and password are required')
}
await payload.resetPassword({ collection, data: { token, password }, req })

Type guard

function hasResetFields(data: unknown): data is { token: string; password: string } {
  return typeof data === 'object' && !!data
    && Object.prototype.hasOwnProperty.call(data, 'token')
    && Object.prototype.hasOwnProperty.call(data, 'password')
}

Try / catch

try {
  await payload.resetPassword({ collection, data, req })
} catch (e) {
  if (e instanceof APIError && e.status === 400) {
    // show 'token and password required' to the user
  } else throw e
}

Prevention

When it happens

Trigger: A `POST /api/<collection>/reset-password` request body omits `token` or `password`; a form submits an empty password field; the reset link's token query param was never transferred into the POST body. Also via Local API with `data: { password }` missing `token`.

Common situations: Frontend posts only the new password, forgetting the token extracted from the email link; a typo/destructure mistake (`data: { token }` instead of `data: { token, password }`); an empty-string password that some clients strip before sending.

Related errors


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