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
niraj kumar 45niraj kumar 45 

triggers exception:Too many retries of batch save in the presence of Apex triggers

I am getting this below error when I am trying to insert more than 10 records of opportunity and if the batch size is more than 10 through Data Loader. I have a after insert trigger and before update tigger on opportunity which updates the fields of oportunity. But this issue is not coming when I change the batch size to 4 in Data loader. Please let me know how can I resolve this issue.

Too many retries of batch save in the presence of Apex triggers with failures: when triggers are present partial save requires that some subset of rows save without any errors in order to avoid inconsistent side effects from those triggers
Ajay TatedAjay Tated
This is standard batch behaviour. When you do not allow partial save on the records, it will retry maximum 3 times. Each time it removes the record which caused error & try to save the batch again. In your case, when batch size is 10 that limit is getting hit. You can try this by allowing partial save and adding error on all the records by checking save result.

1 more point no need to perform additional updated operation in after insert trigger if you want to update same object. You can move that  code to before insert trigger without need to update record explicitely.

Mark this as best answer if it helps.
niraj kumar 45niraj kumar 45
Can you please let me know where can i make the changes as i need to write after insert trigger only because I need the id of the record. we cannot modify in before trigger as it will take several modification in our application:
 
Ajay TatedAjay Tated
You need to change your update call to Database.update(listToUpDate, false) and then iterate over SaveResult to add error on respective records.
In order to add error on respective record you will have to maintain index separately as indexes will be same for list you are going update and save
result list will be same.

Something like this:

Database.SaveResult[] srList = Database.update(listToUpDate, false);
Integer index= 0;
// Iterate through each returned result
for (Database.SaveResult sr : srList) {
    if (sr.isSuccess()) {
        
        System.debug('Successfully inserted record. record ID: ' + sr.getId());
    }
    else {
    
        String errorMsg ='';
        // Operation failed, so get all errors                
        for(Database.Error err : sr.getErrors()) {
            
            errorMsg +=  err.getMessage() +'\n';
            
        }
        listToUpDate[index].addError(errorMsg);
    }
    index++;
}
niraj kumar 45niraj kumar 45
Hi Ajay,

Thank you for you quick response.
Below is my trigger code:
trigger OpportunityDealSizeBulky on Opportunity(after insert, before update){ 
      
    List <opportunity> oppList = new List<opportunity>();
    //if(checkRecursiveAfterInsertOpp.runOnce()){  
    if(Trigger.isInsert && Trigger.isAfter){
           system.debug('sze--'+Trigger.new.size());
          
                OpportunityCAT_Updated_Range.getOppDetails(Trigger.new, true);  
        
        
        Map<Id,String> mapErrorMessage = OpportunityCAT_Updated_Range.errorMessage;
        system.debug('mapErrorMessageinsert===='+mapErrorMessage);
        
       for(opportunity oppToUpdate:Trigger.New){
                system.debug('sze1--'+Trigger.new.size());
                if(mapErrorMessage.containsKey(oppToUpdate.Id)){
                     if(mapErrorMessage.get(oppToUpdate.Id)!=NULL && mapErrorMessage.get(oppToUpdate.Id)!=''){
                           oppToUpdate.addError(mapErrorMessage.get(oppToUpdate.Id));
                           //break;  
                       }
                }
            
       
      }  
                                                                                 
    }
  // } 
    
        if(Trigger.isUpdate && Trigger.isbefore){ 
          
                 OpportunityCAT_Updated_Range.getOppDetails(Trigger.New, false);
             
             oppList = OpportunityCAT_Updated_Range.updateListOpp;
             Map<Id,String> mapErrorMessage = OpportunityCAT_Updated_Range.errorMessage;
             system.debug('mapErrorMessage===='+mapErrorMessage);
             system.debug('list of opp from helper class is:'+oppList);
             //if(oppList!=NULL && !oppList.isEmpty()){
                for(opportunity oppToUpdate:Trigger.New){
                   
                         if(mapErrorMessage.containsKey(oppToUpdate.Id)){
                                system.debug('mapErrorMessage:###'+mapErrorMessage);
                              if(mapErrorMessage.get(oppToUpdate.Id)!=NULL && mapErrorMessage.get(oppToUpdate.Id)!=''){  
                               system.debug('mapErrorMessage:==='+mapErrorMessage);
                                   oppToUpdate.addError(mapErrorMessage.get(oppToUpdate.Id));
                                  
                                   //break;        
                                }
                            }
                             for(opportunity o: oppList){
                                oppToUpdate.Deal_Size__c = o.Deal_Size__c;
                                oppToUpdate.Risk_Category__c = o.Risk_Category__c ;
                                oppToUpdate.Sensitive_Geography__c = o.Sensitive_Geography__c ;
                                oppToUpdate.New_Geography__c = o.New_Geography__c ;
                                oppToUpdate.Specific_Services__c = o.Specific_Services__c ;
                                oppToUpdate.New_Services__c = o.New_Services__c;
                    }
                }
             //}
                         
                          
          }
      //}
}

I need to call helper class which sends me error msg with opportunity id. Now can you please tell me the code that you have mentioned I need to include in both after insert and before update trigger? 
Ajay TatedAjay Tated
Can you share code in helper/class where opportuinity is actually getting updated ?