I'm getting this error from a class referenced by an Email Service. From what I understand, the error is kicked off when a reference is made to a list which exceeds the number of items in the list.

Help : Help Documentation

In this case, the class is referencing the attachments included in an email. Ultimately, it intends to re-save the attachment as a file in a SF record. Here are the lines which are causing the error. I will also include the entire class later in this post :

     //Set file Name
     fileName  = fileStartName+pCR.Contact__r.Name +' )';
     version = Integer.valueOf(attachment.Name.split('V1.')[1].removeEnd('.csv').isNumeric() ? attachment.Name.split('V1.')[1].removeEnd('.csv') : '0');  
                                fileName +=  '.csv';

In the debug logs the line beginning with 'version' seems to be the line causing the error.

I am confused by the code so would really appreciate any input which you can provide on why this error is happening. I do know that the code will work some times. Thank you very much.

I have included the whole class here :

    global Messaging.InboundEmailResult handleInboundEmail(Messaging.inboundEmail email,Messaging.InboundEnvelope envelop)
        Messaging.InboundEmailResult result = new Messaging.InboundEmailResult();
        //String to hold message
        String message = '';
        String fileStartName = '';
        String fileEndName = '';
        String fileName = '';
        Integer version = 0;
        //List to hold Error log records
        List<Error_Log__c> errorLogs = new List<Error_Log__c>();
        //Get From Address
        String fromAddress = email.FromAddress;
        //Get Contact
        Contact contactRecord;
        List<Contact> contacts = [SELECT Id , Name , AccountId FROM Contact WHERE Email =: fromAddress ORDER BY Name DESC LIMIT 1];
        if(contacts.size() > 0)
            contactRecord = contacts[0];    
        if (email.binaryAttachments != null && email.binaryAttachments.size() > 0) 
            //Map to hold the Funder Contact Role Details with Funder
            Map<Id, Program_Contact_Role__c> mapPCRsWithProgram = new Map<Id, Program_Contact_Role__c>();
            //List to hold Content versions
            List<ContentVersion> contentVersions = new List<ContentVersion>();
           for(integer i =0, s = email.binaryattachments.size(); i < s; i++) 

          if(email.binaryAttachments[i].mimeTypeSubType.equals('application/vnd.ms-excel') || email.binaryAttachments[i].mimeTypeSubType.equals('text/csv') ||email.binaryAttachments[i].filename.contains('.csv')) 

                    System.debug('Attachment matched a criteria');
                    //Get Attachment details
                    List<String> attachmentSplitsByRows = new List<String>();
                    //Insatnce of attachemnts
                    Attachment attachment = new Attachment();
                    // Get attachment name and body
                    attachment.Name = email.binaryAttachments[0].filename;
                    attachment.Body = email.binaryAttachments[0].body;
                    System.debug('Attachment Body '+(attachment.Body).toString());
                    //Convert to string
                    String attachmentBody = (attachment.Body).toString();
                    attachmentBody = attachmentBody.unescapeCsv();
                    //Split the data by new line 
                    attachmentSplitsByRows = attachmentBody.split('\n');
                    //Set to hold the Onbording Ids
                    Set<Id> setOnbordingIds = new Set<Id>();
                    //Map to hold the Onbording Record
                    Map<Id, Program_Onboarding__c> mapProgramOnboardings = new Map<Id, Program_Onboarding__c>();
                    //Set to hold the Program Onbording ids to check Funder is already approved or not 
                    Set<Id> setOfProgOnboardingIds = new Set<Id>();
                    //List of Milestone to create a new Milestone
                    List<Milestone__c> milestones = new List<Milestone__c>();
                    Boolean firstRow = true;
                    //Loop over the Attachments
                    for(String csvRow : attachmentSplitsByRows)
                        //Skip header row
                            //Get the onbording details
                            List<String> attachmentSplitByColumns = csvRow.split(',');
                            //Add Onbording Id in set
                        firstRow = false;
                    firstRow = true;
                    //Check onbordings
                    if(setOnbordingIds.size() > 0) {
                        //Get Onboardings
                        mapProgramOnboardings = new Map<Id, Program_Onboarding__c>([Select Id, Supplier__c, Supplier__r.Supplier__c, Funder__c, Program__c From Program_Onboarding__c Where Id IN : setOnbordingIds]);
                        //Get Milestones
                        for(Milestone__c ml : [Select Id , Onboarding__c FROM Milestone__c WHERE Onboarding__c IN: setOnbordingIds AND Milestone_Type__c =: Constants.PROGRAM_MILESTONE_MILESTONE_TYPE_APPROVED_BY_FUNDER])
                        //Set to hold the Program Details
                        Set<Id> setProgramIds = new Set<Id>();
                        //Loop over the Onboardings
                        for(Program_Onboarding__c pO : mapProgramOnboardings.values())
                        //Set file Name
                        fileStartName = 'Response - '+attachment.Name.split('.csv')[0].trim()+' - ( ';
                        //Get Funder Program Contact Role
                        for(Program_Contact_Role__c pCR : [Select Id, Program_Name__c, Funder__c , Contact__c , Contact__r.Name From Program_Contact_Role__c Where Program_Name__c IN : setProgramIds AND Contact__r.Email =: fromAddress AND RecordTypeId =: Constants.PROGCONTACTROLE_RT_ID_FUNDER]){
                            mapPCRsWithProgram.put(pCR.Program_Name__c, pCR);
                            //Set file Name
                            fileName  = fileStartName+pCR.Contact__r.Name +' )';
                            version = Integer.valueOf(attachment.Name.split('V1.')[1].removeEnd('.csv').isNumeric() ? attachment.Name.split('V1.')[1].removeEnd('.csv') : '0');  
                            fileName +=  '.csv';
                            //Insert File under Program
                            // convert from string to blob
                            Blob tempBlob = attachment.Body;
                            // convert base64 encode from the blob
                            string csvFile = EncodingUtil.base64Encode(tempBlob);
                            //Decoding base64Data
                            String base64Data = EncodingUtil.urlDecode(csvFile, 'UTF-8');
                            ContentVersion contentVersionData = new ContentVersion();
                            contentVersionData.Title = fileName;
                            contentVersionData.PathOnClient = '/' + fileName;
                            contentVersionData.FirstPublishLocationId = pCR.Program_Name__c;
                            contentVersionData.VersionData = EncodingUtil.base64Decode(base64Data);
                            contentVersionData.IsMajorVersion = true;
                            //Add content version
                    System.debug('attachmentSplitsByRows '+attachmentSplitsByRows[0].split(',').size());
                    if(attachmentSplitsByRows.size()>0 && attachmentSplitsByRows[0].split(',').size() > 8){
                        //Loop over the Onbording details
                        for(String csvRow : attachmentSplitsByRows){
                            //Skip header row
                                //Get the onbording details
                                List<String> attachmentSplitByColumns = csvRow.split(',');
                                //Get last column
                                Integer lastColumn = attachmentSplitByColumns.size();
                                if(attachmentSplitByColumns.size() > 8){
                                    //Check Approved by funder is Yes or True then update program onboarding status to 'Trading Set Up - Pending Supplier'
                                    if(attachmentSplitByColumns.size() > 8 && String.isNotBlank(attachmentSplitByColumns[0]) && !setOfProgOnboardingIds.contains(attachmentSplitByColumns[0]) && (attachmentSplitByColumns[lastColumn-1].trim().equalsIgnoreCase('True') || attachmentSplitByColumns[lastColumn-1].trim().equalsIgnoreCase('Yes'))){
                                        //Update onbording
                                        mapProgramOnboardings.get(attachmentSplitByColumns[0]).Status__c = Constants.ONBOARDING_STATUS_PENDING_SUPPLIER;
                                        //Add a new Milestone
                                        milestones.add(milestone(mapProgramOnboardings.get(attachmentSplitByColumns[0]), mapPCRsWithProgram, Constants.PROGRAM_MILESTONE_MILESTONE_TYPE_APPROVED_BY_FUNDER));
                                    } else if(attachmentSplitByColumns.size() > 8 && String.isNotBlank(attachmentSplitByColumns[0]) && !setOfProgOnboardingIds.contains(attachmentSplitByColumns[0]) && (attachmentSplitByColumns[lastColumn-1].trim().equalsIgnoreCase('False') || attachmentSplitByColumns[lastColumn-1].trim().equalsIgnoreCase('No'))){
                                        //Update onbording
                                        mapProgramOnboardings.get(attachmentSplitByColumns[0]).Status__c = Constants.ONBOARDING_STATUS_BUYER_REVIEW;
                                        //Add a new Milestone
                                        milestones.add(milestone(mapProgramOnboardings.get(attachmentSplitByColumns[0]), mapPCRsWithProgram, Constants.PROGRAM_MILESTONE_MILESTONE_TYPE_BUYER_REVIEW_REQUESTED));
                                    }else if(setOfProgOnboardingIds.contains(attachmentSplitByColumns[0])){
                                        message = 'Funder File is already processed.';
                                            //Add error Log
                                            errorLogs.add(errorLog(mapProgramOnboardings.get(attachmentSplitByColumns[0]) , message , contactRecord));
                                    }else if(attachmentSplitByColumns.size() > 8 && (!attachmentSplitByColumns[lastColumn-1].trim().equalsIgnoreCase('Yes') || !attachmentSplitByColumns[lastColumn-1].trim().equalsIgnoreCase('No'))){
                                        message = 'Funder replies back with '+attachmentSplitByColumns[lastColumn-1].trim()+' instead of Yes or No.';
                                        //Add error Log
                                        errorLogs.add(errorLog(mapProgramOnboardings.get(attachmentSplitByColumns[0]) , message , contactRecord));
                                        message = 'Funder replies back with blank value instead of Yes or No.';
                                        //Add error Log
                                        errorLogs.add(errorLog(mapProgramOnboardings.get(attachmentSplitByColumns[0]) , message , contactRecord));
                            firstRow = false;
                        message = 'Funder file formate is not correct , please check funder file.';
                        //Add Error log
                        errorLogs.add(errorLog(null , message , contactRecord));
                    //check size
                    if(mapProgramOnboardings.size() > 0)
                        update mapProgramOnboardings.values();
                    //Check milestone list
                    if(milestones.size() > 0)
                        insert milestones;
                    //Check content versions
                    if(contentVersions.size() >0)
                        insert contentVersions;
                }catch(Exception ex){

Thank you very much.

  • ftr - As I'm sure you can tell, there are additional lines to the class. I just didn't include the further lines because I don't think they are relevant and I wanted to keep the confusion as low as possible. – Zoom_v Oct 9 '20 at 14:47

The error is saying that your List is too short to have any values at index 1. It may be empty or only contain one element. You will need to update the code to handle the possibility that Attachment.Name doesn't contain 'V1.'. If the Name doesn't have this string in it, then split takes the entire Name and places it into a List at the first index.

String name = 'readme.csv';

List<String> version = name.split('V1.');
System.debug('version = ' + version);
// 'version = (readme.csv)'

name = 'readmeV1.csv';
version = name.split('V1.');
System.debug('version = ' + version);
// 'version = (readme, csv)'

Additionally, the line with version is fairly hard to read with all of the operations on one line. This is likely better and protects against the error you're seeing:

//Set file Name
fileName = fileStartName + pCR.Contact__r.Name + ' )';
String attachmentName = attachment.Name;
List<String> splitName = attachmentName.removeEnd('.csv').split('V1.');

if(splitName.size() >= 2 && splitName[1].isNumeric()) {
    version = Integer.valueOf(splitName[1]);
} else {
    version = 0;

fileName += '.csv';

This fixes your current situation, but be prepared for two more possibilities: the major version number going to 2 (or higher) and the minor version not being an Integer (such as '1.2').

  • Thank you so much for your help here. I am trying to understand your solution. I apologize for the rookie questions I'll have - First of all, I don't understand the first section in that it is hard-coding 'readme.csv' for String name. Also, I don't understand where that whole first section goes within the class. Should this all just replace the 3 lines I included in the first secion of my post ? Again, I apologize for the rookie questions - and unfortunately I'll have more. I really appreciate the help so much. Thank you. – Zoom_v Oct 9 '20 at 16:06
  • 1
    My first code block is just to demonstrate how the String.split method works when the string passed into split doesn't exist in the string trying to be split. It simply returns the original string inside of a list. – nbrown Oct 9 '20 at 16:25
  • oh, ok. Thanks for that again @nbrown. Another question - I understand that the class ultimately intends to insert the file with a file name that is in sequence with previously saved files (ie readme - V1.0.csv ; readme - V1.1.csv ; ...) But I don't understand why this class needed to do a split on the email's attachment in the first place. I wouldn't think the email's attachment would ever have a 'V1' in it. So is the split just being done to remove it if it does by coincidence have it ? Or am I totally not understand it ? – Zoom_v Oct 9 '20 at 17:41
  • 1
    That's an implementation question I don't think anyone here would be able to answer. As far as I am aware there's no way to enforce the data coming in to have "V1." in it, so the way this is working and the intended outcome need to be looked at. – nbrown Oct 9 '20 at 17:59
  • 1
    No, it's coming from the name of the attachment. You're banking on the attachment name always having "V1." inside of it when I doubt that's always going to be the case. What happens if it becomes V2, V3, V4, etc.? That's what I am warning about. – nbrown Oct 12 '20 at 14:56

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.