diff --git a/packages/payload/src/collections/operations/utilities/update.ts b/packages/payload/src/collections/operations/utilities/update.ts index e371a09a1..93bbeff3d 100644 --- a/packages/payload/src/collections/operations/utilities/update.ts +++ b/packages/payload/src/collections/operations/utilities/update.ts @@ -237,9 +237,11 @@ export const updateDocument = async < overrideAccess, req, skipValidation: - shouldSaveDraft && - collectionConfig.versions.drafts && - !collectionConfig.versions.drafts.validate, + (shouldSaveDraft && + collectionConfig.versions.drafts && + !collectionConfig.versions.drafts.validate) || + // Skip validation for trash operations since they're just metadata updates + Boolean(data?.deletedAt), } if (publishSpecificLocale) { diff --git a/test/trash/collections/Posts/index.ts b/test/trash/collections/Posts/index.ts index f1a7867ff..d37cdb6be 100644 --- a/test/trash/collections/Posts/index.ts +++ b/test/trash/collections/Posts/index.ts @@ -12,6 +12,7 @@ export const Posts: CollectionConfig = { { name: 'title', type: 'text', + required: true, }, ], versions: { diff --git a/test/trash/int.spec.ts b/test/trash/int.spec.ts index 0f0b9a49c..e7d3a0e6a 100644 --- a/test/trash/int.spec.ts +++ b/test/trash/int.spec.ts @@ -648,6 +648,43 @@ describe('trash', () => { }) }) + describe('trashing documents with validation issues', () => { + it('should allow trashing documents with empty required fields (draft scenario)', async () => { + // Create a draft document with empty required field + const draftDoc = await payload.create({ + collection: postsSlug, + data: { + title: '', // Empty required field + _status: 'draft', + }, + draft: true, + }) + + expect(draftDoc.title).toBe('') + expect(draftDoc._status).toBe('draft') + + // Should be able to trash the document even with empty required field + const trashedDoc = await payload.update({ + collection: postsSlug, + id: draftDoc.id, + data: { + deletedAt: new Date().toISOString(), + }, + }) + + expect(trashedDoc.deletedAt).toBeDefined() + expect(trashedDoc.title).toBe('') // Title should still be empty + expect(trashedDoc._status).toBe('draft') + + // Clean up + await payload.delete({ + collection: postsSlug, + id: draftDoc.id, + trash: true, + }) + }) + }) + describe('deleteByID operation', () => { it('should throw NotFound error when trying to delete a soft-deleted document w/o trash: true', async () => { await expect( diff --git a/test/trash/payload-types.ts b/test/trash/payload-types.ts index b490d8560..95880b376 100644 --- a/test/trash/payload-types.ts +++ b/test/trash/payload-types.ts @@ -134,7 +134,7 @@ export interface Page { */ export interface Post { id: string; - title?: string | null; + title: string; updatedAt: string; createdAt: string; deletedAt?: string | null;