payloadcms/payload · error · APIError

Cannot restore a version of a trashed document (ID: ${parent

Error message

Cannot restore a version of a trashed document (ID: ${parentDocID}). Restore the document first.

What it means

Thrown at packages/payload/src/collections/operations/restoreVersion.ts:133 with HTTP 403 (FORBIDDEN) during restoreVersion when the collection has `trash: true` enabled and the parent document is currently soft-deleted (`deletedAt` is set). Restoring a version onto a trashed document is disallowed because the document must first be restored from the trash bin.

Source

Thrown at packages/payload/src/collections/operations/restoreVersion.ts:133

    const findOneArgs: FindOneArgs = {
      collection: collectionConfig.slug,
      locale: 'all',
      req,
      where: combineQueries({ id: { equals: parentDocID } }, accessResults),
    }

    // Get the document from the non versioned collection
    const doc = await req.payload.db.findOne<TData>(findOneArgs)

    if (!doc && !hasWherePolicy) {
      throw new NotFound(req.t)
    }
    if (!doc && hasWherePolicy) {
      throw new Forbidden(req.t)
    }

    if (collectionConfig.trash && doc?.deletedAt) {
      throw new APIError(
        `Cannot restore a version of a trashed document (ID: ${parentDocID}). Restore the document first.`,
        httpStatus.FORBIDDEN,
      )
    }

    // /////////////////////////////////////
    // fetch previousDoc
    // /////////////////////////////////////
    const prevDocWithLocales = await getLatestCollectionVersion({
      id: parentDocID,
      config: collectionConfig,
      payload,
      query: findOneArgs,
      req,
    })

    // originalDoc with hoisted localized data
    const validationLocale = payload.config.localization

View on GitHub (pinned to 00c58b35c0)

Solutions

  1. Restore the parent document from trash first (e.g., `payload.update({ collection, id, data: { deletedAt: null } })` with trash enabled), then call restoreVersion.
  2. Hide the 'Restore version' action in the UI when the parent document is trashed.
  3. Check `doc.deletedAt` before attempting version restore.

Example fix

// before
await payload.restoreVersion({ collection: 'pages', id: versionId }) // parent is trashed

// after — restore the parent from trash first
await payload.update({ collection: 'pages', id: parentDocID, data: { deletedAt: null } })
await payload.restoreVersion({ collection: 'pages', id: versionId })
Defensive patterns

Strategy: validation

Validate before calling

// Restore the parent from trash before restoring a version
const parent = await payload.findByID({ collection: 'pages', id: parentDocID, overrideAccess: true })
if (parent?.deletedAt) {
  // parent is trashed — restore it first
  await payload.update({ collection: 'pages', id: parentDocID, data: { deletedAt: null } })
}
await payload.restoreVersion({ collection: 'pages', id: versionId })

Type guard

const isTrashed = (doc: { deletedAt?: string | null } | null): doc is { deletedAt: string } =>
  Boolean(doc && typeof doc.deletedAt === 'string' && doc.deletedAt)

if (!isTrashed(parent)) {
  await payload.restoreVersion({ collection: 'pages', id: versionId })
}

Try / catch

try {
  await payload.restoreVersion({ collection: 'pages', id: versionId })
} catch (err) {
  if (err instanceof APIError && err.status === 403 && /trashed document/.test(err.message)) {
    // restore the parent from trash, then retry restoreVersion
  } else throw err
}

Prevention

When it happens

Trigger: A document was soft-deleted (moved to trash) and a user (or automation) attempts to restore one of its versions before restoring the parent document itself; the admin UI lists versions for a trashed doc and allows the restore action.

Common situations: Trash/soft-delete feature enabled on the collection; orphaned UI state showing version actions for trashed docs; automation that runs restoreVersion without checking trash status.

Related errors


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