function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Charni Wiggins 13Charni Wiggins 13 

How to return a list from an invocable apex action back to the flow, when there are multiple flow interviews

Record triggered flow, working absolutely fine for one record but receiving the following error when we create multiple records..

The number of results does not match the number of interviews that were executed in a single bulk execution request.
 
public with sharing class FlowInvokableOpportunityLineItemHandler {


    @InvocableMethod(
        label = 'Opportunity Product from Opportunity Accounts'
        description = 'Given list of Accounts return list of OLIs from that account and parent account'
    )

    public static List<List<OpportunityLineItem>> runOppLineItems( List<ID> accIds ) {
        List<OpportunityLineItem> oLIs = new List<OpportunityLineItem>();
        List<Id> accountsIds = new List<Id>();
        List<Account> accIncParents = [SELECT Id, ParentId FROM Account WHERE Id IN: accIds];

        for (Account acc : accIncParents){
            if(acc.ParentId == NULL){
                accountsIds.add(acc.Id);
            }
            else{
                accountsIds.add(acc.Id);
                accountsIds.add(acc.ParentId);
            }
        }
        system.debug('accountsIds >>>>' + accountsIds);

        List<Opportunity> opps = [SELECT Id FROM Opportunity WHERE AccountId IN : accountsIds AND Opportunity.StageName != 'Closed Lost'];
        List<OpportunityLineItem> oLI = [SELECT Id, Product_Family__c, Product2.Name FROM OpportunityLineItem WHERE OpportunityId in :opps];
        
        system.debug('OLI >>>>' + oLI);
        List<List<OpportunityLineItem>> itemListList = new List<List<OpportunityLineItem>>();
        //add the list opps to the list of lists
        itemListList.add(oLI);
        system.debug('itemListList >>>>' + itemListList);

        // send list of lists to the Flow	
        return itemListList;        

    }
}

 
John Pipkin 14John Pipkin 14
@Charni, 

Invokable Methods take a list as an intake and return a list. The size of those lists must match. Flows are bulkified so when you have multiple records going through the flow, all of the records get passed into the method at once. For instance, lets say that you have 2 records being updated and both call this method.
 
public static [Result 1, Result 2] doInvoke( [Input 1, Input 2] intake) {
  for( ... input : intake) {
    // this is the input parameters from each record
  }

  return new ...[] {Result from Record 1, Result from Record 2};
}

So it looks like your List<List<OpportunityLineItem>> contains 1 List<OpportunityLineItem> that has all of the accounts in the List<Id>. You will need to split those up into sepatate lists by account Id. 

I don't know your exact use case but if I had to guess, here would be something that may work:
public with sharing class FlowInvokableOpportunityLineItemHandler {


    @InvocableMethod(
            label = 'Opportunity Product from Opportunity Accounts'
            description = 'Given list of Accounts return list of OLIs from that account and parent account'
    )

    public static List<List<OpportunityLineItem>> runOppLineItems( List<ID> accIds ) {
        List<OpportunityLineItem> oLIs = new List<OpportunityLineItem>();
        List<Id> accountsIds = new List<Id>();
        List<Account> accIncParents = [SELECT Id, ParentId FROM Account WHERE Id IN: accIds];

        for (Account acc : accIncParents){
            if(acc.ParentId == NULL){
                accountsIds.add(acc.Id);
            }
            else{
                accountsIds.add(acc.Id);
                accountsIds.add(acc.ParentId);
            }
        }
        system.debug('accountsIds >>>>' + accountsIds);

        List<Opportunity> opps = [SELECT Id FROM Opportunity WHERE AccountId IN : accountsIds AND Opportunity.StageName != 'Closed Lost'];
        Map<Id, List<Opportunity>> oppMap = new Map<Id, List<Opportunity>>();
        // group opps by account id
        for(Opportunity opp : opps) {
            if(!oppMap.containsKey(opp.AccountId)); {
                oppMap.put(opp.AccountId, new List<Opportunity>());
            }
            oppMap.get(opp.AccountId).add(opp);
        }
        List<OpportunityLineItem> oLI = [SELECT Id, Product_Family__c, Product2.Name FROM OpportunityLineItem WHERE OpportunityId in :opps];
        Map<Id, List<OpportunityLineItem>> oliMap = new Map<Id, List<OpportunityLineItem>>();
        // group olis by opportunity
        for(OpportunityLineItem o : oli) {
            if(!oliMap.containsKey(o.OpportunityId)) {
                oliMap.put(o.OpportunityId, new List<OpportunityLineItem>());
            }
            oliMap.get(o.OpportunityId).add(o);
        }
        
        system.debug('OLI >>>>' + oLI);
        List<List<OpportunityLineItem>> itemListList = new List<List<OpportunityLineItem>>();
        // now iterate over intake ids
        for(Id acctId : accIds) {
            List<OpportunityLineItem> acctOLIs = new List<OpportunityLineItem>();
            Opportunity[] lstOpps = oppMap.get(acctId);
            // if no opps
            if(lstOpps == null) {
                itemListList.add(acctOLIs);
                continue;
            }
            // loop through each opp to get olis
            for(Opportunity opp : lstOpps) {
                OpportunityLineItem[] oppOlis = oliMap.get(opp.Id);
                // if no OLIs
                if(oppOlis == null) {
                    itemListList.add(acctOLIs);
                    continue;
                }
                // add all of the olis for this opp
                acctOLIs.addAll(oppOlis);
                
            }
            // we added all of the olis, so associate this result to the acctId
            itemListList.add(acctOLIs);
        }
        
        system.debug('itemListList >>>>' + itemListList);

        // send list of lists to the Flow	
        return itemListList;

    }
}

Hope this helps!