From 203f72116af661828669774fc5ce2e4bd497b2fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Fri, 15 May 2026 13:05:21 +0200 Subject: [PATCH] fix(advanced-filter): exclude many-to-one relations from relation target picker MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The backend supports a single-hop relation traversal. If the user picked a many-to-one relation field as the target, the dispatcher would substitute the target id into fieldMetadataId and recurse — the inner call has relationTargetFieldMetadataId set to null, so it falls through to the per-type RELATION case which expects a UUID list, not a primitive value. The UI offered a traversal that the backend silently demoted to filter-by-id. Filter many-to-one fields out of the target list so only one-hop traversals can be composed. --- .../AdvancedFilterRelationTargetFieldSelectMenu.tsx | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRelationTargetFieldSelectMenu.tsx b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRelationTargetFieldSelectMenu.tsx index 1f9e94725b3..f12f71aea7f 100644 --- a/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRelationTargetFieldSelectMenu.tsx +++ b/packages/twenty-front/src/modules/object-record/advanced-filter/components/AdvancedFilterRelationTargetFieldSelectMenu.tsx @@ -62,9 +62,17 @@ export const AdvancedFilterRelationTargetFieldSelectMenu = ({ ? sourceFieldMetadataItem.relation.targetObjectMetadata.id : null; - const { filterableFieldMetadataItems: relationTargetFields } = + const { filterableFieldMetadataItems: allTargetFields } = useFilterableFieldMetadataItems(targetObjectMetadataId ?? ''); + // The backend supports a single hop only. Exclude many-to-one relations + // from the target list so the user can't compose multi-hop traversals + // (e.g. Person → Company → ParentCompany) that the dispatcher would + // collapse back to a filter-by-id on the intermediate relation. + const relationTargetFields = allTargetFields.filter( + (field) => !isManyToOneRelationField(field), + ); + if ( !isDefined(sourceFieldMetadataItem) || !isManyToOneRelationField(sourceFieldMetadataItem)