Bug: record-event publisher crashes with "e.split is not a function" when matching a live-query filter against a SELECT-type field
Environment
Self-hosted, Twenty v2.36.0.
Bug description
The object-record event publisher evaluates GraphQL record filters in-process to decide which live queries receive an event (object-record-event-publisher.ts → isRecordMatchingRLSRowLevelPermissionPredicate → the per-field-type matchers). When the filter being evaluated targets a SELECT-type field, the code path ends in isMatchingStringFilter (twenty-shared utils), which calls .split on the value. If the filter value is not a plain string — for example a multi-select filter carrying an array, or a stale client-side cached filter whose value shape the matcher does not expect — the publisher crashes:
ERROR [Event] e.split is not a function
TypeError: e.split is not a function
at mr (packages/twenty-shared/dist/utils-*.js)
at F (...), at Xi (...)
at is-record-matching-rls-row-level-permission-predicate.util.js:211:60
at Array.every (<anonymous>)
at isRecordMatchingRLSRowLevelPermissionPredicate (...util.js:93:35)
at ...util.js:43:75 / :43:56 (group recursion)
at object-record-event-publisher.js:312:151
Impact: the crash happens per published record event, so event delivery to the matching live query fails repeatedly and the log fills with the error. It does not affect reads/writes themselves, only the live-update path. We observed it recurring whenever a particular screen was open (its cached query filter trips the matcher on every related event).
Note the per-field-type matcher for SELECT compares the value as a string, while SELECT fields can legitimately carry array-shaped filters (e.g. in: [...] from multi-select components), so the matcher and the front-end filter grammar disagree.
Expected behavior
The publisher should evaluate (or safely skip) filters whose value shape it cannot match, instead of throwing inside event delivery.
Notes
Happy to provide more details or test a fix. We also have a related (now fixed on our side) finding in the same evaluator's caller chain — see #25932 for the workspaceMembers/GetCurrentUser half-removed-member issue.
Source: twentyhq/twenty