Bug Description
When contacts have custom fields with dots in their names (e.g., prefix.key), dynamic segments fail to match any contacts. The same issue affects workflow condition evaluation and email template variable rendering.
Steps to Reproduce
- Create contacts with custom data fields that contain dots in the key name (e.g.,
{"app.plan": "premium"})
- Create a dynamic segment with a filter on that field (e.g.,
data.app.plan equals premium)
- Observe that the segment matches zero contacts, even though contacts exist with that value
- Rename the field to use a different separator (e.g.,
app|plan) and the segment works correctly
Root Cause
Contact custom field data is stored as a flat JSON object in the data column:
However, three code paths split field names on . to build path lookups, which interprets prefix.key as a nested path (data.prefix.key) instead of a literal key (data["prefix.key"]):
SegmentService.buildJsonFieldCondition — jsonPath.split('.') creates a multi-element Prisma JSON path array, causing the query to look for nested data -> prefix -> key instead of the flat key data -> "prefix.key"
WorkflowExecutionService.resolveField — splits on every . to traverse the data object, failing to find the literal key
template.ts getValue — path.split('.').reduce() tries to traverse nested objects instead of looking up the literal key
Impact
- Dynamic segments: Conditions on dotted custom fields match zero contacts
- Workflow conditions: CONDITION steps referencing dotted fields always evaluate to false
- Email templates:
{{data.prefix.key}} renders as empty in emails
Expected Behavior
Custom field names containing dots should be treated as literal key names, not as nested path separators. Users should be free to use any characters (including dots) in their custom field names.
Bug Description
When contacts have custom fields with dots in their names (e.g.,
prefix.key), dynamic segments fail to match any contacts. The same issue affects workflow condition evaluation and email template variable rendering.Steps to Reproduce
{"app.plan": "premium"})data.app.plan equals premium)app|plan) and the segment works correctlyRoot Cause
Contact custom field data is stored as a flat JSON object in the
datacolumn:{"prefix.key": "value"}However, three code paths split field names on
.to build path lookups, which interpretsprefix.keyas a nested path (data.prefix.key) instead of a literal key (data["prefix.key"]):SegmentService.buildJsonFieldCondition—jsonPath.split('.')creates a multi-element Prisma JSON path array, causing the query to look for nesteddata -> prefix -> keyinstead of the flat keydata -> "prefix.key"WorkflowExecutionService.resolveField— splits on every.to traverse the data object, failing to find the literal keytemplate.tsgetValue—path.split('.').reduce()tries to traverse nested objects instead of looking up the literal keyImpact
{{data.prefix.key}}renders as empty in emailsExpected Behavior
Custom field names containing dots should be treated as literal key names, not as nested path separators. Users should be free to use any characters (including dots) in their custom field names.