Multi-Select Fields: Why a Sync Wipes the Other Values
When an automation adds one value to a multi-select field and the existing values disappear, the cause is that HubSpot, Salesforce, Airtable, and Notion all treat a multi-select write as a replacement of the whole set, not an append. Each exposes a different append syntax or none at all, so the durable fix is the same in every tool: read the current values, merge as a set, and write the full set back, comparing as a set so ordering differences never trigger a spurious update.
An automation adds one tag to a contact and the other four tags disappear. That is not a bug in the connector. HubSpot, Salesforce, Airtable, and Notion all treat a write to a multi-select field as a replacement of the whole set, so an "add one value" step that sends one value is an instruction to keep exactly one value. Each of them exposes a different append mechanism, or none at all, which is why the vendor-specific fix you found for one system does nothing in the next. The rule that holds across all of them is read, merge as a set, write the full set back.
The write is a replace, not an add
A multi-select field looks like a row of checkboxes, and checkboxes suggest that ticking one leaves the others alone. The API model is different. The field holds one value, and that value happens to be a collection. When you update it, you supply the new collection, and the old one is gone.
HubSpot's CRM API documentation is explicit: multiple checkboxes values are sent as a semicolon-separated string with no spaces, and "if the property has an existing value, the leading semicolon will append the values instead of overwriting the value." Read that sentence the other way around. Without the leading semicolon, the write overwrites. The import path behaves identically. HubSpot's import documentation says to add a semicolon before the first value to append, and that a row without it replaces the existing property value.
Salesforce has no append syntax at all. Its Field Types reference describes multi-select picklist selections as "a string containing a series of attributes delimited by semicolons." An update sets that string. If you want to add "Support" to a record whose field currently holds "Sales;Billing", you send "Sales;Billing;Support", which means you had to read the record first.
Airtable says the quiet part in its own field model documentation for multiple select: "this array-type field will override the current cell value when being updated. Be sure to spread the current cell value if you want to keep the currently selected choices." Notion's multi_select property value is an array of option objects and you send the array you want the page to have.
Four systems, one behavior, four ways of expressing it. The operator who learned the HubSpot semicolon trick and then pointed the same automation at Salesforce has just wiped a field.
What each system actually does with a multi-value write
We keep this table pinned when building any sync that touches tags, categories, product interests, or any other field where a record can carry several values at once. Every row was checked against the vendor's current documentation in September 2026.
| System and field | How the value travels | A plain write with one value | How to add without wiping | An option that does not exist yet |
|---|---|---|---|---|
| HubSpot multiple checkboxes | Semicolon-separated string, no spaces: value 1;value 2 | Replaces the whole set | Prefix the payload with a semicolon: ;value 3. Works for the API and for imports. Workflows have a separate append-or-replace toggle on the set-property action. | Must be created before an import; the documentation requires the options to exist first |
| Salesforce multi-select picklist | Semicolon-delimited string | Replaces the whole set | No append syntax. Query the current string, add the value, write the full string back. | A restricted picklist rejects it |
| Airtable multiple select | Array of option name strings | Overrides the cell, per Airtable's docs | Read the cell, spread the current array into the new one, write it | Rejected with INVALID_MULTIPLE_CHOICE_OPTIONS unless typecast is on, in which case Airtable creates the option |
| Notion multi_select | Array of objects with name, id, color | You send the full array | Read the page property, add the object, write the full array | Added to the data source schema if the integration has write access to it |
| Zapier, into a field with no multi-value support | Line items flattened to a comma-separated list | Whatever the target does with a text write | Formatter Line-item to Text with an explicit separator, then a target-side append | Depends entirely on the target |
Three things in that table decide how you build the step.
First, the append affordance is not portable. HubSpot's leading semicolon is a HubSpot fact. Airtable's advice to spread the current value is a read-then-write instruction in disguise. Salesforce hands you nothing. Assume any "update record" action is a replace unless the vendor documents otherwise for that field type, and test it on a record that already has three values before you trust it.
Second, the delimiter is a per-system fact. HubSpot and Salesforce both use semicolons in their string form, but HubSpot's documentation forbids the space after it and Salesforce's example includes one. Airtable and Notion do not serialize at all; they hand you an array. The moment your automation passes a multi-select through a text field, a spreadsheet cell, or an email body, you have chosen a delimiter, whether you meant to or not.
Third, unknown values behave differently everywhere. We covered who is allowed to invent an option in dropdown values that don't match between systems, and the same governance rule applies here with one extra wrinkle: a multi-select field accumulates. A typo option created through typecast puts "plumbing" and "Plumbing" side by side on the same record until a person cleans it.
Three failure signatures and what each one tells you
The symptom points at the cause more precisely than most operators expect. A multi-select field goes wrong in one of three recognizable shapes.
The other values vanished. One value survives, the rest are gone, and the survivor is the one your automation touched. This is the plain replace. Open the step that writes the field and look at what it sends. If it sends one value, that is your answer. Then check how far the damage spread: an automation that runs on every form submission has been doing this to every submitter since it went live, and the values it removed are not in any log unless you built the run record we recommend for every automation.
One value became two, or two became one. A record that should carry "Plumbing, Heating" as a single service category arrives downstream as "Plumbing" and "Heating," or the reverse: two legitimate values arrive as one string with a separator inside it. This is a delimiter collision. Somewhere in the path, the set was serialized to text with a character that appears inside at least one option name, and then split on that same character. Zapier's own line items guide states that when an action or field does not support line items, "they'll be treated as a comma-separated list instead," and a comma is exactly the character that shows up in option names like "Kitchen, Bath" or "Sales, Inc." Notion is the one system here that documents a ban on the delimiter inside a value; its API reference states that commas are not valid in select values. Everywhere else, the guard is yours to build.
The field updates on every run and nobody changed it. A two-way sync writes the same multi-select field back and forth, every pass, with no human touching either side. Each write stamps the record, which re-triggers the other direction, and you find out because the modified-by column on both systems shows the integration user and the last-modified time is always a minute ago. This is an ordering problem. "Sales;Support" and "Support;Sales" are one set and two strings, and the sync is comparing strings. We wrote about the general shape of this in two-way sync that overwrites data; multi-select fields are a common way it shows up on a field nobody edited.
Each signature has a different fix, and none of the three is fixed by remapping.
Read, merge as a set, write the full set
The pattern that works in every one of these systems has four steps, and the second one is where the real work is.
Read the record's current value for the field immediately before the write, not from the trigger payload. A trigger payload is a snapshot from when the event fired. If two automations touch the same record within a few seconds, which is normal when a form submission fires a scoring workflow and a tagging workflow at once, the snapshot is stale and the second writer silently removes what the first one added. It is the same divergence that makes an automation unable to find a record it just created: what you hold in memory and what the system holds are no longer the same.
Normalize both the current value and the incoming value into a set. Split on the system's documented delimiter, trim whitespace, drop empties, deduplicate, and match against the option list on the internal value rather than the display label. You now have two sets, not two strings.
Merge with an explicit operation. Adding a tag is a union. Removing a tag is a difference. Replacing the tags is an assignment, and if that is what the business rule wants, say so in the step name so the next person does not mistake it for an append. Most wiped fields come from an assignment that someone thought was a union.
Compare before you write. Sort both sets into a canonical order, and if the merged set equals the current set, skip the write. This one check kills the third failure signature outright, because a reordered field no longer counts as a change, and it removes the pointless writes that eat API quota and re-trigger the other side of a two-way sync. Only when the sets differ do you serialize into the target's form and write the complete set.
In n8n this is a Code node between the lookup and the update, a dozen lines of split, trim, Set, spread, and sort. In Make it is a join() over a merged array with the separator the target expects. In Zapier it is a Formatter split on the current value, a Line Itemizer to combine, and a Line-item to Text step with the target's delimiter, or a Code step if that chain gets long. None of these are hard. The mistake is skipping the read because the update action "already knows" the record, when what it knows is the record as it was when the trigger fired.
Where this pays off is any workflow that accumulates history on a record: products purchased, events attended, services quoted. On a field-service platform, a customer's service categories arrive through the web form, phone intake, and the technician app, and every one of those paths has to do the read-merge-write. The day one of them shortcuts to a plain update is the day a customer who has bought HVAC, plumbing, and electrical work becomes an electrical-only customer in every report.
Removing one value is its own operation
Appending is half the job. Removing one value without clearing the rest is the other half, and it is the one vendors were slowest to support. The HubSpot Ideas thread requesting a workflow action to remove a single value from a multiple checkboxes property was opened in April 2020 and marked Delivered in January 2026, which tells you how long operators lived with append-or-clear as the only two options. Until then the honest workarounds were a custom-code step or an export, edit, and re-import.
Read-merge-write handles removal for free: it is a set difference instead of a union. That is the strongest argument for owning this logic in a code step rather than relying on the platform's native action. The native action gives you whatever operations the vendor shipped. Your own step gives you union, difference, and assignment, in every target, with the same compare-before-write guard.
What to do next
Pick the multi-select field that matters most, usually the one that drives segmentation or routing, and pull up every automation that writes to it. For each one, open the step and answer one question: does it send the whole set, or one value? Any step that sends one value without the target's documented append affordance is a replace, and it has been replacing since it was turned on. The records that now show a single value where several should be are your cleanup list.
If you are building or fixing a sync between a CRM and an operations platform and want the set logic, the option governance, and the change detection done once and applied to every field that needs it, that is the kind of workflow automation system we build. Start by telling us which two systems disagree at /contact.
Frequently Asked Questions
SOURCES & CITATIONS
- CRM API guide: Properties (multiple checkboxes values and appending) — HubSpothttps://developers.hubspot.com/docs/guides/api/crm/properties
- Field Types: Multi-Select Picklist Field Type — Salesforcehttps://developer.salesforce.com/docs/atlas.en-us.api.meta/api/field_types.htm
- Web API: field model (multiple select) — Airtablehttps://airtable.com/developers/web/api/field-model
- The line items guide: Automatically copy details from orders and invoices — Zapierhttps://zapier.com/blog/formatter-line-item-automation/
About Alexey Yushkin
Alexey is the founder of GENERAL INFORMATICS LLC. He designs and ships AI and automation systems for businesses and operators across the US.
Related reading
Want this kind of system in your business?
We build practical AI and automation systems for operators. Send us your current workflow and we will show you what to automate first.
