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
Ross Hopkins 8Ross Hopkins 8 

Before Insert trigger on Product2 causing "List index out of bounds"

Hi,
I have written a trigger that runs on Product2 Before Insert. The outcome is that a set of comma delimited key:value pairs stored in a text field are copied into their respective custom fields.

In the most part this is working, however peridoically I receive the following error:
Sandbox

Apex script unhandled trigger exception by user/organization: 0055xxxxxxxwzY/00Dxxxxxx8W
Source organization: xxxxxxxxteA (null)
Shopify_Split_Tags_Field_v1: execution of BeforeInsert

caused by: System.ListException: List index out of bounds: 1

()
The code is:
trigger Shopify_Split_Tags_Field_v1 on Product2 (before insert) {
    for(Product2 p: trigger.new){
        if(p.wk_shopify__Shopify_Tag__c != null){
            List<string>tags = p.wk_shopify__Shopify_Tag__c.split(',');
            
            if(tags.size() > 0) {
                for(string t: tags){
                    if(t.contains('age')){
                        p.Asset_Age__c = t.split(':')[1];
                    }
            
                    if(t.contains('assetcondition')){
                        p.Asset_Condition__c = t.split(':')[1];
                    }
            
                    if(t.contains('location')){
                        p.Asset_Location__c = t.split(':')[1];
                    }
            
                    if(t.contains('manufacturer')){
                        p.Asset_Manufacturer__c = t.split(':')[1];
                    }
                    
                    if(t.contains('make')){
                        p.Asset_Make__c = t.split(':')[1];
                    }
            
                    if(t.contains('model')){
                        p.Asset_Model__c = t.split(':')[1];
                    }
                    
                    if(t.contains('shipping')){
                        p.Shipping_Code__c = t.split(':')[1];
                    }
                
                    if(t.contains('power')){
                        p.Asset_Power__c = t.split(':')[1];
                    }
            
                    if(t.contains('rentalstatus')){
                        p.Asset_Rental_Status__c = t.split(':')[1];
                    }
            
                    if(t.contains('serial')){
                        p.Asset_Serial__c = t.split(':')[1];
                    }
            
                    if(t.contains('subcatcode')){
                        p.Asset_Subcatcode__c = t.split(':')[1];
                    }
                }
            }
        }    
    }
}
I've been reading about what the error means, and it would seemingly be that I'm trying to read an array element that doesn't exist. I added the size check of tags to try and avoid this, but that hasn't worked.

What am I missing?

Thanks,
Ross
 
Best Answer chosen by Ross Hopkins 8
Ravi Dutt SharmaRavi Dutt Sharma
Hi Ross,

In all the if conditions, you are accessing the element at index 1 without checking if the array contains 2 elements or not. You should modify all the if conditions and introduce a size check before accessing the array elements. Example below:
 
if(t.contains('age')){
	var splitArray = t.split(':');
	if(splitArray.length > 1){
		p.Asset_Age__c = splitArray[1];
	}
}

 

All Answers

Deepali KulshresthaDeepali Kulshrestha
Hi Ross,

If you attempt to access an element at row 1, 
The code will throw an error if no data exist at row 1.
It is a  good practice to check whether there are records 
in the list before accessing any element from that list.

I hope you find the above solution helpful. If it does, please mark as Best Answer to help others too.

Thanks and Regards,
Deepali Kulshrestha
Ross Hopkins 8Ross Hopkins 8
Hi Deepali,

Thanks for your response. Line 06 was my attempt to address this - if that evaluated to FALSE then there is no data to process and the trigger should end.

How could it be that there are values found  ( if(tags.size() > 0) == TRUE ) but then access element 1 fails?

Thanks,
Ross
Ravi Dutt SharmaRavi Dutt Sharma
Hi Ross,

In all the if conditions, you are accessing the element at index 1 without checking if the array contains 2 elements or not. You should modify all the if conditions and introduce a size check before accessing the array elements. Example below:
 
if(t.contains('age')){
	var splitArray = t.split(':');
	if(splitArray.length > 1){
		p.Asset_Age__c = splitArray[1];
	}
}

 
This was selected as the best answer
Ross Hopkins 8Ross Hopkins 8
Hi Ravi,

Ah, now I see! That shouldn't ever happen - there should always be a key:value pair, never a key: alone. I suspect I have a test Product2 record with "corrupted" data.

However, I can see that it would be best practice to follow your advice.

Thank you!

Ross
Ajay K DubediAjay K Dubedi
Hi Ross,
Firstly for best practices please separate the trigger and handler class, and also you should check all conditions i.e. for every situation and also any variable is not going to be null.
Try this code:
In my org this is working fine:
trigger:
trigger hopify_Split_Tags_Field_v1 on Product2 (before insert) {

    if(trigger.isInsert && trigger.isBefore) {
        Shopify_Split_Tags_Field_v1_Handler.Shopify_Split_Tags_Field_v1_Function(trigger.new);
    }  
}

Handler_Class:
public class Shopify_Split_Tags_Field_v1_Handler {
    
    public static void Shopify_Split_Tags_Field_v1_Function(List<Product2> prodList) {
        List<string> tags = new List<string>();
        system.debug('prodList---->' + prodList);
        try {
            if(prodList.size() > 0) {
                for(Product2 p : prodList) {
                    
                    if(p.wk_shopify_Shopify_Tag__c != null){
                        tags = p.wk_shopify_Shopify_Tag__c.split(',');
                    }
                    system.debug('tags---->' + tags);
                    if(tags.size() > 0) {
                        for(string t: tags) {
                            if(t.contains('age:')){
                                String temp = t.split(':')[1];
                                if(!isEmpty(temp)) {
                                    p.Asset_Age__c = temp;
                                }
                            }
                            if(t.contains('assetcondition:')){
                                String temp = t.split(':')[1];
                                if(!isEmpty(temp)) {
                                    p.Asset_Condition__c = temp;
                                }
    //change code as per your requirement.
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            System.debug('The following exception has occurred: ' + e.getMessage());
            System.debug('The following Line : ' + e.getLineNumber());
        }
    }
}
I hope you find the above solution helpful. If it does, please mark as Best Answer to help others too.
Thanks,
Ajay Dubedi