Skip to main content
Multi-select fields (fields whose type is Multi-Select on a layout, stored internally as MULTI_PICKLIST) hold several selected options in a single value. That shape works cleanly on the record itself, but it behaves differently in each place you might reference it downstream — calculations, an Execute Script action, a Repeat for Each loop, or a Send API Request body. This page names the shape, says which action to pick for each need, and gives the working pattern. If you’re here because of the specific error Invalid Type Error at line 1, position N: MULTI_PICKLIST, jump to In calculations.

The two shapes you’ll encounter

Multi-picklist fields. A field configured as Multi-Select on an Element or Table layout. A single cell holds several selected options. Elementum stores the underlying type as MULTI_PICKLIST. Multi-value text from Data Mine. When a Data Mine trigger fires, a multi-value text column in the payload serializes as an array of objects like [{"value":"WD","type":"TEXT"}, ...] rather than plain text. This is a different problem from a multi-picklist field — it’s a text or JSON payload whose value happens to be array-shaped. See Flattening a Data Mine array payload into plain text for the specifics; the rest of this page is about multi-picklist fields on a record.

Which action to use

Pick the action that matches what you’re trying to do with the selections. Every row below has a working pattern later on this page.

In Execute Script

Multi-select inputs come through as an array of objects with named properties, not an array of primitive strings. What the object exposes depends on how the multi-select field is configured — a static option list and a data-source-backed multi-select map into the Inputs panel differently.

The runtime shape

Given a multi-select field mapped as an input parameter, the value at input.parameters.<parameterName> is an array where each item is an object. The object’s properties are the ones you expose in the Inputs panel:
The value is an array in every expected case:
  • Zero selections — an empty array [].
  • Exactly one selection — an array of length 1, not a bare object. Call .map() unconditionally rather than normalizing with Array.isArray(x) ? x : [x].
  • Several selections — one item per selection.
Because the value can still arrive as null in edge cases, treat every list input as though it might be null or missing. The ?? [] pattern is safe whether the input is null, missing, or already an array:

Configuring the input mapping

Every multi-select input in the Script Configuration → Inputs panel starts with a Parameter name — that’s the JavaScript variable you’ll reference through input.parameters.<parameterName>. The rows nested underneath control which properties of each selected item are exposed inside the script. Two behaviors, depending on how the source field is configured:
  • Static option list. The Inputs panel shows one locked row with label in both Select Field and Parameter. No + Add Field control. Each item in the resulting array has exactly one property — label. This applies to static single-select fields too (with the same locked label behavior), but the value comes through as an array only for multi-select.
  • Data-source-backed multi-select (options come from records of an Object, an API-powered dropdown, or a similar dynamic source). The Inputs panel shows a + Add Field control. Each field you add has three inputs:
Only the properties you expose here are available to the script. If a script needs an additional field from the source object later, come back to the Inputs panel and add it — the Output Schema regenerates when you next click Execute.

Iterating each selection

Loop over the array and reach into whichever property you exposed. For a static multi-select, that property is always label:
For a data-source-backed multi-select, use the Parameter name you configured for each field:
If you only need to act on each selection in a downstream action (create a record per, send an email per, and so on), skip the script entirely and use Repeat for Each directly on the field. Execute Script is the right choice when you need to transform the collection — aggregate, filter, reshape — before handing it off.

Aggregating into a comma-separated string

There is no calculation function that aggregates a multi-picklist into a delimited string (see In calculations). The working pattern is Execute Script:
Return csv from the script and reference it in downstream actions — for example, mapping it into a text field with Update Record Fields, or into a message body in Post Comment or Send Email Notification. For a data-source-backed multi-select, swap the .map(tag => tag.label) for whichever property you want to aggregate:

Passing multi-select values into a JSON API body

The JSON Input field on the Send API Request action expects a plain JSON string, not a structured object. Build the payload in Execute Script, JSON.stringify() it, and map the resulting string into JSON Input. This pattern decouples payload construction from the API action — you can swap the script’s inputs without touching the API step, and reuse the same body across several Send API Request actions.
Then map payload into the Send API Request action’s JSON Input field. On the wire the request body becomes:
What the receiving API sees depends entirely on how you structure the object before stringifying. Common variants:
  • JSON array of strings{ tags: (input.parameters.tags ?? []).map(t => t.label) }
  • JSON array of full objects{ tags: input.parameters.tags ?? [] } (each item keeps every property you exposed in the Inputs panel)
  • Comma-separated string{ tags: (input.parameters.tags ?? []).map(t => t.label).join(', ') }
For the general JSON.stringify requirement on this action and the failed to convert input data to params error you’ll see if you skip it, see the Send API Request reference.

In Repeat for Each

The Repeat for Each action accepts a multi-picklist field directly as its Collection. You do not need to bridge through Execute Script or a Search Records action first. Inside the loop, each property you exposed on the selected item becomes a separate value reference in the picker (type $ in any inner action’s fields). For a static multi-select, that’s a single Label entry. For a data-source-backed multi-select, it’s one entry per exposed field, prefixed with the parameter name — Addresses - Title, Addresses - ID, and so on. Two loop-level helpers are always available:
  • Is First Item — checkbox, true on the first iteration.
  • Is Last Item — checkbox, true on the last iteration.
When to prefer Repeat for Each over Execute Script:
  • You want to run one action (or a small block of actions) per selection without transforming the collection.
  • The per-selection logic is visible in the automation builder rather than tucked inside JavaScript — easier for reviewers and future maintainers to read.
  • No aggregation is needed. If you need a totalled number or a joined string across selections, use Execute Script instead.

In calculations

There is no supported calculation pattern that aggregates a multi-picklist field into a delimited string, or otherwise operates on all of its selections at once. STRING_AGG and STRING_AGG_UNIQUE accept single-value text supplied through a related-field aggregation only, and passing a MULTI_PICKLIST field to either raises:
This applies everywhere calculations run — calculated columns on a Table, formulas on an Element layout, and the Run Calculation action. What to do instead. If your ultimate need is a text value derived from the selections (a comma-separated summary, a count, a joined description), do the work in Execute Script and, if the value needs to live on a record, write it back with Update Record Fields. If your need is per-selection processing, use Repeat for Each directly. For the full error catalog and the analogous Data Mine limitation, see Calculations troubleshooting → Multi-value and array-shaped values.