payloadcms/payload · warning · Locked

Document with ID ${id} is currently locked by another user a

Error message

Document with ID ${id} is currently locked by another user and cannot be modified.

What it means

A `Locked` error thrown by `checkDocumentLockStatus` when a collection document is being modified by a request that does not hold the lock. Another user lock entry exists in the `locked-documents` collection, the lock holder is a different user, and the lock has not expired (within `lockDocuments.duration` seconds, default 300).

Source

Thrown at packages/payload/src/utilities/checkDocumentLockStatus.ts:94

    // If there's a locked document, check lock conditions
    const lockedDoc = lockedDocumentResult?.docs[0]
    if (lockedDoc) {
      const lastEditedAt = new Date(lockedDoc?.updatedAt).getTime()
      const now = new Date().getTime()

      const lockDuration =
        typeof lockDocumentsProp === 'object' ? lockDocumentsProp.duration : lockDurationDefault

      const lockDurationInMilliseconds = lockDuration * 1000
      const currentUserId = req.user?.id

      // document is locked by another user and the lock hasn't expired
      if (
        lockedDoc.user?.value !== currentUserId &&
        now - lastEditedAt <= lockDurationInMilliseconds
      ) {
        throw new Locked(finalLockErrorMessage)
      }
    }
  }

  // Perform the delete operation regardless of overrideLock status
  await payload.db.deleteMany({
    collection: lockedDocumentsCollectionSlug,
    // Not passing req fails on postgres
    req: payload.db.name === 'mongoose' ? undefined : req,
    where: lockedDocumentQuery,
  })
}

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Wait for the lock to expire (default 300s / 5 min) or have the locking user close the document.
  2. Pass `overrideLock: true` in the Local API call if the operation should force through (use with caution).
  3. Reduce `lockDocuments.duration` if locks linger too long.
  4. Use `payload.db.deleteMany` on the `locked-documents` collection to manually clear a stuck lock if needed.

Example fix

// before
await payload.update({
  collection: 'posts',
  id,
  data: { title: 'New' },
  // overrideLock defaults to true in Local API, but admin UI sets false
})

// after -- explicitly override when appropriate
await payload.update({
  collection: 'posts',
  id,
  data: { title: 'New' },
  overrideLock: true,
})
Defensive patterns

Strategy: try-catch

Validate before calling

// Before updating, check if the document is locked by another user
const locks = await payload.find({
  collection: 'payload-locked-documents',
  where: {
    and: [
      { 'document.relationTo': { equals: collectionSlug } },
      { 'document.value': { equals: id } },
    ],
  },
  depth: 1,
})
const lock = locks.docs[0]
if (lock && lock.user?.value !== currentUserId && Date.now() - new Date(lock.updatedAt).getTime() < 300000) {
  throw new Error('Document is locked')
}

Try / catch

try {
  await payload.update({ collection, id, data, overrideLock: false })
} catch (e) {
  if (e.name === 'Locked') {
    // wait, notify user, or pass overrideLock: true if appropriate
  } else throw e
}

Prevention

When it happens

Trigger: A PATCH/DELETE on a collection document where `overrideLock` is `false` (default for the admin UI), `lockDocuments` is not `false`, and a recent `locked-documents` entry exists with a different `user.value` and an `updatedAt` within the lock duration window.

Common situations: Two admin users editing the same document concurrently; a user navigated away without saving, leaving a stale lock that has not expired yet; an automated script modifies a document a user currently has open in the admin panel; the lock duration is set very long and locks are not being released.

Related errors


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