Workaround: Salesforce Flow Picklist-Related Invalid Type Error
Tags: salesforce, database, errors
Published: 2019-11-07 20:01:27

---
title: Workaround: Salesforce Flow Picklist-Related Invalid Type Error
description:  "INVALID_TYPE_ON_FIELD_IN_RECORD"
published: true
date: 2019-11-06 15:00:00 UTC
tags: salesforce,database,errors
canonical_url: https://katiekodes.com/salesforce-error-invalid-type-picklist-flow/
---

I received an `INVALID_TYPE_ON_FIELD_IN_RECORD` / `value not of required type` error that made no sense when editing a Salesforce flow.  Turns out it's a known error.  Here's how I got around it.

## Status Quo

Within an org I administer, one department's salespeople occasionally need to add new **Contact** records to Salesforce in a very strict fashion.

From their perspective, they have very little to say about the new Contact besides **name**, **email**, and **which product** the Contact is interested in buying.

However, from the operations manager's perspective, there's all sorts of "extra" data entry that needs to happen with **custom objects**, **Opportunity** _(to sell the product in question to that Contact)_, etc.

What we decided to do was lock down Contact creation so that sales-team users couldn't do it, but give them a "system mode" data entry screen that would do it for them _(as well as all the other auxiliary work)_.

I built the user interface to this "internal form" as a **Screen Flow** _(to save myself Visualforce or Lightning Component coding hassle)_ and delegated the "system-mode data entry" work to **Invocable Apex**.

The architecture of my Flow was that:

1. The **Screen** collected **name**, **email**, and **product**.
2. The Flow then set `FirstName`, `LastName`, and `Email` on a **Contact**-typed **Flow Variable**.
3. The Flow passed this **Flow Variable** over to some **Invocable Apex**.
4. The **Invocable Apex** actually does the DML `INSERT` of the Contact in system mode.

## Change Request

The operations manager said it'd be nice to have salespeople also enter a value for **LeadSource** when creating a new Contact, and asked me to add that to the form's user interface.

It sounded easy-peasy.  Two steps:

1. Collect "lead source" in the **screen**.
2. Have the Flow set the Contact-typed **flow variable**'s `LeadSource` in addition to `FirstName`, `LastName`, and `Email` before passing the **flow variable** to **invocable Apex**.

## Error

Unfortunately, I ran into [this](http://jforcesf.blogspot.com/2019/05/flow-that-passes-sobject-with-picklist.html) [issue](https://twitter.com/jforcesf/status/1130544494473043968) _(thanks, for saving me so much headache by blogging all your Tweets for easy search engine findability, [Jason](https://twitter.com/jforcesf)!)_:

> "Flow that passes SObject with Picklist field as input to Invocable Apex will fail with INVALID_TYPE_ON_FIELD_IN_RECORD error"

The original "known issue" on Salesforce's web site that Jason linked to no longer works, but his tweet let me know what was going on when I got the following error:

> Error element Create_new_Contact (FlowActionCall).
> An Apex error occurred: System.DmlException: Insert failed. First exception on row 0; first error: INVALID_TYPE_ON_FIELD_IN_RECORD, Lead Source: value not of required type: Blah Blah Blah: [LeadSource] 

---

## The Fix

**The heart of what I did** is to make it so I'm **technically _not_** passing my **Invocable Apex Method** a `Contact` that has a value populated on a picklist-typed field anymore _(which is what triggers the nonsensical error)_.

Instead, I pass it two parameters -- a `Contact` and a `String` -- then combine them inside the Apex.

I altered the input parameter signature of my **Invocable Apex Method**.

* Formerly, it required a single **Contact** input parameter
	* _(Note to coders:  remember that Invocable-Apex-land, that's a `List<Contact>` parameter you need to `[0]`.  Don't ask me why.)_
* Now it requires a more complex set of parameters.
	* It still takes the **Contact** input parameter _(into which my **Apex Action** in **Flow** passes the Contact-typed **Flow Variable**)_, but 
	* Now it _also_ takes a **String**-typed input parameter _(into which my **Apex Action** in **Flow** passes the value that an end user chose for "Lead Source" in the Flow's Screen)_.
        * Personally, I used [Apex-defined data types](https://katiekodes.com/flow-apex-defined-data-types/) to "clump" the two input parameters together into a single parameter, but I'm pretty sure I also could have done it with a 2-parameter method that took a `List<Contact>` and a `List<String>`.

Then, within the Apex, before doing `INSERT` againt the `SObject` representing the `Contact` passed to it, it sets `LeadSource` on that `SObject` to be the _**other**_ value I passed into Apex from the flow.

> * Note that what I _don't_ do is try to set the value of `LeadSource` on the **Flow Variable** _before_ it makes its way into the Apex.
> * The Flow itself still just sets `FirstName`, `LastName`, and `Email` on the Contact-typed flow variable.

I also had to:

1. Change my Apex unit test and confirm it still passed after changing my invocable method signature.
2. Change my Flow's invocation of the invocable method to use the new input parameters _(Flow's UI made it **really** easy -- thanks, Salesforce Flow team!)_

### Want To See Code?

For code-heads, here's the old Apex:

```java
public class CreateContactInvocable {
    
    @InvocableMethod(label='Create new Contact' description='Returns a Contact ID if the work was done correctly, NULL if not.')
    public static List<Id> doContactCreate(List<CreateContactInvocable> inputContactDetailsList) {
        Id cid = NULL;
        if (inputContactDetailsList.size() > 0) {
            Contact c = inputContactDetailsList[0];
            if (c != NULL) {
                if (c.Id != NULL) {
                    cid = c.Id;
                }
                else if (c.LastName != NULL && c.LastName != '' && c.FirstName != NULL && c.FirstName != '' && c.Email != NULL && c.Email != '') {
                    INSERT c;
                    cid = c.Id;
                }
            }
        }
        return new List<Id>{cid};
    }
}
```

And here's the new Apex:

```java
public class CreateContactInvocable {
    
    @AuraEnabled @InvocableVariable public Contact the_contact;
    @AuraEnabled @InvocableVariable public String the_lead_source;
    
    @InvocableMethod(label='Create new Contact' description='Returns a Contact ID if the work was done correctly, NULL if not.')
    public static List<Id> doContactCreate(List<CreateContactInvocable> inputContactDetailsList) {
        Id cid = NULL;
        if (inputContactDetailsList.size() > 0) {
            Contact c = inputContactDetailsList[0].the_contact;
            String lead_source = inputContactDetailsList[0].the_lead_source;
            if (c != NULL) {
                if (c.Id != NULL) {
                    cid = c.Id;
                }
                else if (c.LastName != NULL && c.LastName != '' && c.FirstName != NULL && c.FirstName != '' && c.Email != NULL && c.Email != '') {
                    c.LeadSource = lead_source;
                    INSERT c;
                    cid = c.Id;
                }
            }
        }
        return new List<Id>{cid};
    }
}
```

The additions are:

1. `@AuraEnabled @InvocableVariable public Contact the_contact;` -- this turns my class into an "Apex-Defined Data Type"
2. `@AuraEnabled @InvocableVariable public String the_lead_source;` -- this turns my class into an "Apex-Defined Data Type"
3. Altering `c` to be `inputContactDetailsList[0].the_contact` instead of `inputContactDetailsList`
4. `String lead_source = inputContactDetailsList[0].the_lead_source;`
5. `c.LeadSource = lead_source;` right before `INSERT c;` _(**this** is the heart of what I did)_