-2

My batch is running without any error in lower environment, but when I scheduled batch apex in Production, it shows this error :First error: Attempt to de-reference a null object. I have tried to use system.debug and if condition to catch null value, but no luck. Also I don't receive any email when batch completes.Can anyone please help here...

 global class CaseOwnerManagerUpdateBatch implements Database.Batchable<sObject>,Database.Stateful,Schedulable 
    {
         Boolean sendMail;
        

        
        global CaseOwnerManagerUpdateBatch() 
        {
            
        }
        
          
        
        global Database.Querylocator start(Database.BatchableContext BC) {
            //Return all open cases owned by a user
            return Database.getQueryLocator([SELECT Id, Case_Owner_Manager__c, OwnerId FROM Case WHERE Status != 'Closed' AND Owner.Type = 'User'  AND RecordType.DeveloperName IN ('Support','Support_New')]);
        }
        
        
    
        
        global void execute(Database.BatchableContext BC,List<Case> scope) {
            Set<Id> userIds = new Set<Id>();
            List<Case> caseUpdateList = new List<Case>();//Create a list that will hold cases that need to be updated
            
            //Iterate through the cases and build a set of owner ids that we can use to query the user object
            for (Case c : scope) {
                userIds.add(c.OwnerId);
            }
            
            //Query the user records for each of these case owners
            Map<Id, User> caseOwners = new Map<Id, User>([SELECT Id, ManagerId FROM User WHERE Id IN :userIds]);
            
            if(!caseOwners.isEmpty()){ 
              
                 //Iterate through the cases and check to see if a manager update is needed
            for (Case c : scope) {
              
                System.debug('case owner starts' + caseOwners);
                System.debug('user id starts' + userIds.add(c.OwnerId));
                System.debug('case owner id starts' + caseOwners.get(c.OwnerId));
                System.debug('manager id starts' + caseOwners.get(c.OwnerId).ManagerId);
                System.debug('Case owner manager' + c.Case_Owner_Manager__c );
                if (c.Case_Owner_Manager__c != caseOwners.get(c.OwnerId).ManagerId) {
                    c.Case_Owner_Manager__c = caseOwners.get(c.OwnerId).ManagerId;
                    caseUpdateList.add(c);
                }
              }
              
             
            }
            
            
            try
            {
                if (caseUpdateList.size() > 0) //If we have any cases that need to be updated, update them
                {
                    
                    Database.update(caseUpdateList, false);
                    
                }
            }
            catch(Exception excep)
            {
                ExceptionLogger.log(excep,new ExceptionLogger.ExceptionData('Update Case Owner Manager on Case', 'CaseOwnerManagerUpdateBatch', 'Batch Apex','Execute Method', 'Case', ''),null);
            }
        }
        
        

        global void finish(Database.BatchableContext BC) 
        {
            
            String emailAlias = System.Label.Case_Owner_Manager_EmailAlias;
            if (!String.isEmpty(emailAlias)) { 
                //send confirmation email notifications
                AsyncApexJob a = [SELECT Id, Status,ExtendedStatus,NumberOfErrors, JobItemsProcessed,TotalJobItems, CreatedBy.Email  FROM AsyncApexJob where Id =:BC.getJobId()];
                
                
                Messaging.SingleEmailMessage mail = new Messaging.SingleEmailMessage();
                String[] toAddresses = new String[] {emailAlias};
                    mail.setToAddresses(toAddresses);
                mail.setSubject('Case Owner Manager Update Batch ' + a.Status);
                mail.setPlainTextBody('records processed ' + a.TotalJobItems +   'with '+ a.NumberOfErrors + ' failures.');
                if ((a.NumberOfErrors != null || sendMail) && !Test.isRunningTest()) 
                {
                    Messaging.sendEmail(new Messaging.SingleEmailMessage[] { mail });
                }    
                
            }
        }
        global void execute(SchedulableContext SC) 
        {
            database.executebatch(new CaseOwnerManagerUpdateBatch());
        }
        
        
    }
3
  • 3
    What line of code exactly throws this exception?
    – sfdcfox
    Aug 18, 2021 at 13:17
  • @sfdcdox if (c.Case_Owner_Manager__c != caseOwners.get(c.OwnerId).ManagerId) this line shows error
    – Avi_SFDC
    Aug 18, 2021 at 13:33
  • Please edit your question with any clarifications. That is not what comments are for.
    – Adrian Larson
    Aug 18, 2021 at 13:43

2 Answers 2

1

Your code will fail if any records are owned by a Queue, because a core assumption of your code is every Case is owned by a User. It is easy enough to just check if the OwnerId is actually found in the Map.

User owner = caseOwners.get(c.OwnerId);
if (owner != null && owner.ManagerId != c.Case_Owner_Manager__c) { ... }
3
  • They do filter by Owner.Type = 'User', though, so that makes it not-so-obvious that the owner could be a queue if it changes between the time the query executes and the execute method handles that record. Also, don't forget about SNO, it can save the extra check.
    – sfdcfox
    Aug 18, 2021 at 14:13
  • Thanks for explanation @sfdcfox. And what about this condition that I am currently checking: if(!caseOwners.isEmpty()) Do we need to check this before if (owner != null && owner.ManagerId != c.Case_Owner_Manager__c) { ... } ?
    – Avi_SFDC
    Aug 18, 2021 at 15:54
  • @Avi_SFDC It's fine. Not strictly necessary, and definitely not a NPE situation. You could write it as if(owner?.ManagerId != c.Case_Owner_Manager__c) { ... }
    – sfdcfox
    Aug 18, 2021 at 15:56
1

i think it's because your property sendEmail is not initiliazed, so if the a.NumberOfErrors is null (a.NumberOfErrors != null || sendMail), the second check of the if statement will be checked and this one will cause exception, example below:

Boolean test;
Boolean firstCondition = false;
system.debug(firstCondition || test);

Try to initialize the sendEmail as false or true like below:

 Boolean sendMail = true;//or false

Other thing that can raise exception, is the caseOwners.get(c.OwnerId), if the owner is a Queue, the caseOwners.get(c.OwnerId).ManagerId will fail, because the queueId was not retrieved in the query of users, you can check if it's a queue or use the safe navigator like these

caseOwners.get(c.OwnerId)?.ManagerId
3
  • Hi @Willian Matheus, I have deliberately not retrieved QueueID in query, as I only want o update Case_Owner_Manager__c lookup field when case type=user, status!=closed and record type =support or support_new
    – Avi_SFDC
    Aug 18, 2021 at 13:38
  • Hi @Avi_SFDC What is shown in your system.debug statement? Aug 18, 2021 at 13:45
  • You could have also changed the condition to sendEmail != false or something.
    – sfdcfox
    Aug 18, 2021 at 14:13

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .