payloadcms / payloadcms/payload
Query Presets: whole admin crashes (notNullString.trim is not a function) when a preset filters a hasMany relationship — Postgres numeric IDs
@r1tsuu is already working on this.
Since Sep 11, 2026.
- Dominant language
- TypeScript
- Stars
- 44.8k
- Forks
- 4.2k
- Avg merge
- 2d 21h
- Merged PRs (30d)
- 53
Description
Describe the Bug
On Postgres (numeric IDs), saving a Query Preset with a filter on a hasMany: true relationship field stores the raw numeric IDs in the preset's where, e.g.:
{ "or": [{ "and": [{ "authors": { "equals": [5] } }] }] }
When the preset selection list later renders, QueryPresetsWhereCell passes each raw filter value to toWords(), which calls .trim() on it. A number has no .trim, so the render throws and the entire admin white-screens ("Application error: a client-side exception has occurred"). There is no error boundary around the cell, so one bad preset makes the collection's presets unusable for every user who can read it.
Uncaught client error:
Uncaught TypeError: (e || "").trim is not a function // minified toWords
at rX (…/chunks/….js:7:94536) // toWords
at ….js:48:134250
at Array.map (<anonymous>) // WhereCell value.map(val => toWords(val))
...
Root cause (verified against the published 3.88.0 packages):
packages/ui→elements/WhereBuilder/Condition/Relationship/index.tsx: the filter multi-select'sonChangeemits rawoption.values. On Postgres these are numbers (on MongoDB they are strings, which is why this mostly goes unnoticed). Saving the preset persists the numeric array into the preset document.packages/ui→elements/QueryPresets/cells/WhereCell/index.tsx(transformWhereToNaturalLanguage, still marked /** @todo: improve this */): for array values it doesvalue.map((val) => toWords(val)).packages/payload→utilities/formatLabels.ts:
const notNullString = inputString || ''
const trimmedString = notNullString.trim() // TypeError when inputString is a number
10-second clean-room proof (pristine package from npm, no app, no DB):
npm i payload@3.88.0 pluralize
node --input-type=module -e "
import { toWords } from 'payload/dist/utilities/formatLabels.js';
toWords(5);"
# TypeError: notNullString.trim is not a function
Related context:
- #12815 covered the "Invalid Date"/
notNullString.trimfamily and is closed, but the numeric-array case above still crashes on 3.88.0. - The server-side twin of this bug (the same
equals: [5]shape breaking the SQL query with a parameter-count mismatch) was fixed in@payloadcms/drizzle(present in 3.88.0:sanitizeQueryValuenow coercesequals/not_equals+ array toin/not_infor relationship/upload fields). The client display path was not given the same treatment.
Suggested fix: coerce intoWords(const notNullString = typeof inputString === 'string' ? inputString : String(inputString ?? '')) — one change covers every caller — orString(val)inWhereCellbefore callingtoWords. Additionally, an error boundary around the preset cells would stop one bad preset from taking down the whole admin.
Link to the code that reproduces this issue
(create with npx create-payload-app@latest -t blank --db postgres; full repro below — happy to push a repo if needed)
Reproduction Steps
- Create a blank Payload app with
@payloadcms/db-postgres(numeric IDs are required to trigger the bug; MongoDB string IDs mask it). - Enable presets and add a
hasManyrelationship inpayload.config.ts:
export default buildConfig({
// ...
queryPresets: {},
collections: [
{
slug: 'posts',
fields: [
{ name: 'title', type: 'text' },
{ name: 'authors', type: 'relationship', relationTo: 'users', hasMany: true },
],
},
],
})
- Log in, create one post.
- In the Posts list view: open Filters → add filter → field Authors → operator equals → pick any user from the dropdown.
- Save this as a new preset ("New Preset").
- Reload the list view and open the preset selection list.
- → "Application error: a client-side exception has occurred", console shows
TypeError: … .trim is not a function. The preset document'swherein the DB contains{"authors":{"equals":[<number>]}}.
Which area(s) are affected?
area: ui
Environment Info
payload: 3.88.0 (also reproduced on 3.79.0)
@payloadcms/db-postgres: 3.88.0
next: 16.x
node: 24.11.1
OS: macOS (darwin arm64)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.