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
Janice MackedonJanice Mackedon 

System.NullPointerException

Hello,
We have an Apex that was built by a priavte consultant back on November 2020 that would update the Owner Field on a Custom Object when their related Approval flow is reassigned to someone else. It appeared to be working fine and on January 13th 2020 we rolled the training on the Custom Object and I started reciving these error emails that same day and have every day since.
Error email body recieved daily:
Apex script unhandled exception by user/organization: 0051N000005gh9F/00D1N000002Jn2i

Failed to process batch for class 'SyncOwnerNameWithApproverBatch' for job id '7073l0000EQiAzS'

caused by: System.NullPointerException: Attempt to de-reference a null object


SF Support pointed me to this knowledge article but since I am and Admin and not a developer, I don't know what that all means or how the code would need to be modified. Also the Code Coverage is showing 0% (0/26) and I was told it has to be above 70%.
Knowledge Article: https://help.salesforce.com/articleView?id=000327918&type=1&mode=1

Below is what is in the Apex Code and I am hoping you all can provide some feedback on what needs to be modified as the Develpoer we used has told me we would have to pay him at this point to figure what the issue is and I don't want to go to my manager without any research of my own if we do need to pay someone again to fix this.

Apex Class Body:
/***************************************************************************************************************
* @author: AutomationChampion
* @Description: Batch Job to Sync Bid Approval Owner to be same as the Approver of the Approval Process
* @LastModifiedBy: Automation Champion
* @version 1.0
*
* Version History
* -------------------------------------------------------------------------------------------------------------
* Version  | Date      | Name      | Details of Change
* -------------------------------------------------------------------------------------------------------------
* 1.0.0    | 24-Nov-2020  | AChamp    | Created
* *************************************************************************************************************/

global class SyncOwnerNameWithApproverBatch implements Database.Batchable<sObject> {
    
    //Variable to hold the Object Prefix of the Bid Approval Object.
    global String keyPrefix = '';
    
    /*************************************************************************************
     * @author: AutomationChampion
     * @Description: Constructor to set the Object Prefix from Scheduleable class
     * @return: void
     * 
     * Change History
     * -----------------------------------------------------------------------------------
     * Date      | Name      | Details of Change
     * -----------------------------------------------------------------------------------
     * 24-Nov-2020  | AChamp    | Created
     * ***********************************************************************************/
    global SyncOwnerNameWithApproverBatch(String keyPrefix) {
        this.keyPrefix = keyPrefix;
        System.debug('@@ KeyPrefix from Scheduler @@ ' + keyPrefix);
    }
    
    /*************************************************************************************
     * @author: AutomationChampion
     * @Description: Start Method of the batch Class
     * @return: QueryLocator
     * 
     * Change History
     * -----------------------------------------------------------------------------------
     * Date      | Name      | Details of Change
     * -----------------------------------------------------------------------------------
     * 24-Nov-2020  | AChamp    | Created
     * ***********************************************************************************/
    global Database.QueryLocator start(Database.BatchableContext bc) {
       String objStartId = '';
       String query = 'SELECT Id, ProcessInstanceId, ProcessInstance.TargetObjectId, Actor.Name FROM ProcessInstanceWorkItem WHERE ProcessInstance.SystemModStamp > = LAST_N_DAYS:1';

        if(String.isNotBlank(keyPrefix)) {
            objStartId = keyPrefix + '000000000000';
            
            query += ' AND ProcessInstance.TargetObjectId > \'' + objStartId + '\'';
        }
        System.debug('@@ Final Query @@ ' + query);
        return Database.getQueryLocator(query);
    }
    
    /*************************************************************************************
     * @author: AutomationChampion
     * @Description: Execute Method to process the logic to identify which Bid Record 
     * Owners should be updated based on the approval process owners
     * @return: void
     * 
     * Change History
     * -----------------------------------------------------------------------------------
     * Date      | Name      | Details of Change
     * -----------------------------------------------------------------------------------
     * 24-Nov-2020  | AChamp    | Created
     * ***********************************************************************************/
    global void execute(Database.BatchableContext bc, list<sObject> scope) {
        
        //Collect the recordIds in a collection
        Set<Id> recordIds = new Set<Id>();
        
        //List to update the OwnerId
        List<BID_Approval__c> lstUpdateBidApproval = new List<BID_Approval__c>();
        
        //Loop through the records to get the RecordId and ApprovalProcess Ids
        for(sObject record :scope) {
            ProcessInstanceWorkItem approvalWorkItem = (ProcessInstanceWorkItem)record;
            recordIds.add(approvalWorkItem.ProcessInstance.TargetObjectId);
        }
        
        
        //Query the BID APPROVALS object 
        Map<Id, BID_Approval__c> mapBidApproval = new Map<Id, BID_Approval__c>([SELECT Id, OwnerId, Owner.Name FROM BID_Approval__c WHERE Id IN :recordIds]);

        for(sObject record :scope) {
             ProcessInstanceWorkItem approvalWorkItem = (ProcessInstanceWorkItem)record;
            
            //Get the Bid Approval record from the MAP 
            BID_Approval__c objBidApproval = mapBidApproval.get(approvalWorkItem.ProcessInstance.TargetObjectId);
            if(objBidApproval.OwnerId <> approvalWorkItem.ActorId) {
                //Assign the Approval Process owner to the ownerid in bid approval record
                objBidApproval.OwnerId = approvalWorkItem.ActorId;
                lstUpdateBidApproval.add(objBidApproval);
            }
            
        }
        
        //Update the Bid Approval Records
        if(lstUpdateBidApproval != null && lstUpdateBidApproval.size() > 0) {
             System.debug('@@ lstUpdateBidApproval @@ ' + lstUpdateBidApproval);
            update lstUpdateBidApproval;
        }
    }
    
    /*************************************************************************************
     * @author: AutomationChampion
     * @Description: Finish Method of the Batch Class
     * @return: void
     * 
     * Change History
     * -----------------------------------------------------------------------------------
     * Date      | Name      | Details of Change
     * -----------------------------------------------------------------------------------
     * 24-Nov-2020  | AChamp    | Created
     * ***********************************************************************************/
    global void finish (Database.BatchableContext bc) {
        
    }
}

 
GauravendraGauravendra
Hi Janice,

I believe the Map mapBidApproval is not returning the Bid record.
Can you please try to put the keycheck before fetching the record from map.
if(mapBidApproval.containsKey(approvalWorkItem.ProcessInstance.TargetObjectId)){
        BID_Approval__c objBidApproval = mapBidApproval.get(approvalWorkItem.ProcessInstance.TargetObjectId);
        if(objBidApproval.OwnerId <> approvalWorkItem.ActorId) {
            //Assign the Approval Process owner to the ownerid in bid approval record
            objBidApproval.OwnerId = approvalWorkItem.ActorId;
            lstUpdateBidApproval.add(objBidApproval);
        }
    }

Hope this helps!
AbhishekAbhishek (Salesforce Developers) 
Janice,

You can try the suggestions as mentioned in the below blog,

https://www.sfdcpoint.com/salesforce/system-nullpointerexception-attempt-to-de-reference-a-null-object/


For further reference, you can check this,

https://www.forcetalks.com/salesforce-topic/how-to-solve-system-nullpointerexception-attempt-to-de-reference-a-null-object-in-salesforce-apex-class/


If it helps you and close your query by marking it as solved so that it can help others in the future.

Thanks.