Describe the Bug
BlocksFeature applies applyBaseFilterToFields to relationship fields inside Lexical blocks. The injected filterOptions calls the target collection's admin.hidden function and returns false when that function returns true for the current user.
Payload's relationship validation interprets filterOptions: false as meaning that every selected ID is invalid. As a result, a user with read access to the target collection cannot save an otherwise valid document containing an already-selected relationship. Saving without changing the relationship fails with Invalid selections.
This couples admin UI visibility to persisted relationship validity. It is also inconsistent with static configuration: the injected filter checks function-based admin.hidden, but does not check admin.hidden: true.
The relevant path is:
@payloadcms/richtext-lexical recursively wraps relationships inside BlocksFeature blocks.
- The wrapper returns
false when admin.hidden({ user }) returns true.
validateFilterOptions adds the relation to falseCollections and rejects the existing ID.
Expected behavior: hiding a collection from a user's admin UI should not invalidate an existing relationship that the same user is authorized to read. At minimum, saving an untouched relationship should not fail validation because of admin.hidden.
This behavior appears to originate from #14985, which added applyBaseFilterToFields for Lexical blocks. The same function-based hidden check also exists in the Lexical internal-link relationship filter, so that path may be affected as well.
Link to the code that reproduces this issue
https://github.com/jenslys/payload/tree/21b39fd4c0678873ea2d3ed91e09980ebfa42582/test/_community
The reproduction is based directly on the v3.87.0 tag.
Reproduction Steps
-
Check out the reproduction commit:
git clone --branch repro/lexical-admin-hidden-validation https://github.com/jenslys/payload.git
cd payload
-
Install dependencies and start the _community fixture:
pnpm install
pnpm exec cross-env PAYLOAD_DATABASE=sqlite pnpm dev _community
-
Open the admin panel and use the configured auto-login user.
-
Open Reproduction Posts and edit Saving this post fails. The seeded Lexical block already references Existing relationship target.
-
Click Save without changing anything.
-
The save fails with an Invalid selections validation error on relatedItem.
-
Change hidden: ({ user }) => Boolean(user) to hidden: false, restart, and repeat. The same post can now be saved.
The logged-in user retains normal read access to hidden-items; only admin.hidden hides the collection.
The reproduction also contains an integration test expressing the expected behavior. It was run with:
pnpm exec cross-env PAYLOAD_DATABASE=sqlite pnpm test:int _community
On Payload 3.87.0 it fails with:
AssertionError: expected 400 to be 200
Content > Related Item: This field has the following invalid selections: 1
Which area(s) are affected?
- plugin: richtext-lexical
- area: core
- area: ui
Environment Info
Payload: 3.87.0
@payloadcms/richtext-lexical: 3.87.0
Next.js: 16.3.0
React: 19.2.7
React DOM: 19.2.7
Node.js: 24.13.0
Package manager: pnpm (upstream reproduction), Bun 1.3.6 (original application)
Database: PostgreSQL in the original application; SQLite in the public reproduction
Operating system: macOS Darwin 25.5.0 arm64
Describe the Bug
BlocksFeatureappliesapplyBaseFilterToFieldsto relationship fields inside Lexical blocks. The injectedfilterOptionscalls the target collection'sadmin.hiddenfunction and returnsfalsewhen that function returnstruefor the current user.Payload's relationship validation interprets
filterOptions: falseas meaning that every selected ID is invalid. As a result, a user with read access to the target collection cannot save an otherwise valid document containing an already-selected relationship. Saving without changing the relationship fails withInvalid selections.This couples admin UI visibility to persisted relationship validity. It is also inconsistent with static configuration: the injected filter checks function-based
admin.hidden, but does not checkadmin.hidden: true.The relevant path is:
@payloadcms/richtext-lexicalrecursively wraps relationships insideBlocksFeatureblocks.falsewhenadmin.hidden({ user })returnstrue.validateFilterOptionsadds the relation tofalseCollectionsand rejects the existing ID.Expected behavior: hiding a collection from a user's admin UI should not invalidate an existing relationship that the same user is authorized to read. At minimum, saving an untouched relationship should not fail validation because of
admin.hidden.This behavior appears to originate from #14985, which added
applyBaseFilterToFieldsfor Lexical blocks. The same function-based hidden check also exists in the Lexical internal-link relationship filter, so that path may be affected as well.Link to the code that reproduces this issue
https://github.com/jenslys/payload/tree/21b39fd4c0678873ea2d3ed91e09980ebfa42582/test/_community
The reproduction is based directly on the
v3.87.0tag.Reproduction Steps
Check out the reproduction commit:
git clone --branch repro/lexical-admin-hidden-validation https://github.com/jenslys/payload.git cd payloadInstall dependencies and start the
_communityfixture:pnpm install pnpm exec cross-env PAYLOAD_DATABASE=sqlite pnpm dev _communityOpen the admin panel and use the configured auto-login user.
Open Reproduction Posts and edit Saving this post fails. The seeded Lexical block already references Existing relationship target.
Click Save without changing anything.
The save fails with an
Invalid selectionsvalidation error onrelatedItem.Change
hidden: ({ user }) => Boolean(user)tohidden: false, restart, and repeat. The same post can now be saved.The logged-in user retains normal read access to
hidden-items; onlyadmin.hiddenhides the collection.The reproduction also contains an integration test expressing the expected behavior. It was run with:
pnpm exec cross-env PAYLOAD_DATABASE=sqlite pnpm test:int _communityOn Payload 3.87.0 it fails with:
Which area(s) are affected?
Environment Info