github →

New request

#20598: Workflow `UPDATE_RECORD` step cleared `emails` field that was not in `objectRecord` / `fieldsToUpdate`

We'll provision a sandbox, run an agent against the issue, and open a draft PR. You can pull the branch and iterate from there.

Issue
sonarly:high

Summary

A workflow UPDATE_RECORD step running on the person object cleared the standard emails.primaryEmail field on a Person record, even though emails was not in the step's objectRecord and not in fieldsToUpdate.

Other unrelated fields on the same record (name, phones, prospects, addressCustom, etc.) were preserved correctly. Only emails was overwritten to empty.

Would appreciate it if a Twenty staff member could look at the specific workflow run referenced below to figure out which code path overwrote emails — we've traced the open-source code paths from UpdateRecordWorkflowActionUpdateRecordServicedataArgProcessor and can't see how emails would end up in the SQL UPDATE.

Environment

  • Twenty Cloud
  • appVersion: v2.5.0
  • Workspace ID: ba6bbd00-32e7-4ede-aa49-508d69daae79
  • Workflow run ID: 3b1a3da6-7fef-4e01-be59-436a36f9766f
  • Action step ID: 2bfd8e67-e302-45a3-bc82-18ab47c17d55 (named "Update person (Retainer)")

Step settings (verbatim from workflow run, only PII redacted)

{
  "input": {
    "objectName": "person",
    "objectRecord": {
      "partnersName": "{{<code-step-id>.partnerName}}",
      "addressCustom": { "addressStreet1": "{{<code-step-id>.clientAddress}}" },
      "partnersEmail": "{{<code-step-id>.partnerEmail}}",
      "partnerAddress": { "addressStreet1": "{{<code-step-id>.partnerAddress}}" },
      "partnerPhoneNumber": {
        "primaryPhoneNumber": "{{<code-step-id>.partnerPhoneNumber}}",
        "primaryPhoneCallingCode": "{{<code-step-id>.partnerPhoneCallingCode}}"
      }
    },
    "fieldsToUpdate": [
      "addressCustom",
      "partnersName",
      "partnersEmail",
      "partnerPhoneNumber",
      "partnerAddress"
    ],
    "objectRecordId": "{{trigger.id}}"
  }
}

Field types involved (all on person):

  • partnersNameTEXT (custom)
  • partnersEmailTEXT (custom; this field is TEXT, not EMAILS, despite the name)
  • addressCustomADDRESS (custom)
  • partnerAddressADDRESS (custom)
  • partnerPhoneNumberPHONES (custom)
  • emailsEMAILS (standard) — not in objectRecord, not in fieldsToUpdate, but cleared

Observed

Trigger snapshot (workflow start):

emails.primaryEmail: "<user@example.com>"
updatedAt:           <T-13 hours>

UPDATE_RECORD step output (stepInfos[<step-id>].result):

emails.primaryEmail: ""           ← cleared
updatedAt:           <step run time>

A different workflow (agreement.upserted trigger) fired ~1 s later and ran a Find Record step on the same Person via independent GraphQL — also returned emails.primaryEmail: "". So the empty value is in the DB, not just a response-shape artifact.

All other fields on the record (name, phones, prospects, addressCustom, searchVector, etc.) were preserved correctly.

Expected

Only fields listed in fieldsToUpdate (and present in objectRecord) should be modified by UPDATE_RECORD. emails should remain untouched.

Impact

Silent data loss — customer email addresses on Person records are being wiped by workflow automation that's only supposed to touch partner / address fields. End user had to manually restore the email afterward, and downstream integrations (a PandaDoc send) failed because the Client recipient ended up with no email.

Notes from our investigation

We pulled the latest main and traced:

  • UpdateRecordWorkflowAction.execute filters objectRecord by fieldsToUpdate and validates field names; emails never enters this set.
  • UpdateRecordService.execute further filters and calls removeUndefinedFromRecord; still no emails.
  • DataArgProcessorService.process iterates only over keys present in the input record.

From a static read of the code, emails should not be touched. We assume the actual cause is either:

  • something in the workspace data source / TypeORM column composition we missed, or
  • a side-effect from another step or trigger firing on the same record in the same transaction

— but we can't confirm without access to the Cloud backend logs. Please advise.

Assessmentadvisory
bug●● medium80% confidence

Workflow update logic unexpectedly overwrites the composite emails field despite it not being included in the step's update payload.

Likely files
  • packages/twenty-server/src/engine/core-modules/workflow/workflow-actions/update-record/*
  • packages/twenty-server/src/engine/core-modules/record/services/update-record.service.ts
  • packages/twenty-server/src/engine/core-modules/data-processor/data-arg-processor.ts
Create the request

This opens a fresh agent run and a draft PR for issue #20598.

Cancel