The problem: why reassignment breaks merge fields
Approval Processes do plenty of work, but they carry a specific blind spot around context, and the null variable issue is where it shows up. Change an approver, by hand or from an automated process, and the email template the approval process fires populates its merge fields with nothing at all.
The reason is that the email alert's context is tied to the ProcessInstanceStep object. Reassign a record and the relationship between the original requestor, the record and the new target approver shifts, so standard merge fields like {!ApprovalRequest.Comments} resolve to null or show stale data. Three patterns get you around the limitation.
Strategy 1: moving from email alerts to flow-driven notifications
The sturdiest fix is to stop using native Approval Process Email Alerts and send the notification from Flow instead. Native alerts carry almost no logic. A Flow-based notification can re-query the record state at the moment it executes, which is the whole point.
The "after-update" approach
Build a Record-Triggered Flow on the ProcessInstanceWorkitem object, which represents a pending approval request, instead of leaning on the standard approval email template.
- Trigger the flow when a record is updated.
- Filter for
ProcessInstanceWorkitemrecords whereActorIdhas changed. - Send the message with the
Send Custom NotificationorSend Emailaction inside the Flow.
Building it this way hands you ActorId, the new approver, immediately, so you can fetch their User profile data and assemble an email body that has actual values in it.
Strategy 2: invocable apex to capture context
When the logic runs past what Flow will do for you, say parsing deep relationship fields that keep coming back null, Invocable Apex earns its keep. Apex lets you run the SOQL yourself and confirm you have the right data before anyone constructs an email out of it.
Here is a simple pattern for an Invocable method to fetch valid approver context:
public class ApprovalContextHandler {
@InvocableMethod(label='Get Valid Approver Info')
public static List<String> getApproverDetails(List<Id> workItemIds) {
List<ProcessInstanceWorkitem> items = [SELECT Actor.Name, ProcessInstance.TargetObjectId
FROM ProcessInstanceWorkitem
WHERE Id IN :workItemIds];
// Process logic here to ensure variables aren't null
return new List<String>{ items[0].Actor.Name };
}
}
Pass the WorkItemId into an Invocable method and you get a clean query. The approval process may forget the context during the redirect. Your code does not.
Strategy 3: the formula field fallback
The blunt option is often the one that survives. If your email template pulls data from the record being approved, stay away from {!ApprovalRequest.FieldName} syntax, which is volatile during reassignments.
Build proxy formula fields on the object being approved instead. Create one called Current_Approver_Name__c, have it use the Approver__r.Name field when that is populated, and fall back to a custom metadata setting or a related lookup when it is not. The template then references {!MyObject__c.Current_Approver_Name__c} and reads the record's current state rather than the volatile state of the Approval Instance.
Troubleshooting checklist for nulls
When a notification arrives with blanks in it, work down in this order.
Check the trigger order first. If your email alert fires before ActorId is updated in the database, the variable is null and nothing about your template is wrong. A Pause element in the Flow gives the database time to commit the new assignment.
Then validate field level security. A variable can hold a value and still arrive empty: if the user triggering the email, or the Automated Process User, lacks FLS on that specific field, Salesforce returns null to prevent data leakage. I have seen teams rebuild a template twice before anyone checks this one.
Then audit the ProcessInstance. Pull the ProcessInstanceWorkitem history in Query Editor. If OriginalActorId and ActorId are identical, the reassignment logic itself never ran, and the null is downstream of that.
Leave a Comment