Trigger Recursion
By the end of this lesson, you'll be able to:
- Explain how a trigger can accidentally cause itself to fire again
- Use a static Boolean flag to prevent runaway recursion
- Recognize the symptoms of an unguarded recursive trigger
Prerequisites: "Avoiding Logic in Triggers"
How a trigger can trigger itself
trigger AccountTrigger on Account (after update) {
for (Account acc : Trigger.new) {
acc.Description = 'Last updated: ' + System.now();
}
update Trigger.new; // this update fires AccountTrigger again!
}
trigger AccountTrigger on Account (after update) {— anafter updatetrigger.for (Account acc : Trigger.new) {— loops over the just-saved records.acc.Description = 'Last updated: ' + System.now();— changes a field in memory.}— closes the loop.update Trigger.new;— performs a freshupdateonAccountrecords — this is Module 9's recursion concept, but happening accidentally through the trigger/DML relationship rather than a method deliberately calling itself.}— closes the trigger.
Warning: Line 5 fires AccountTrigger again, which updates again, which fires again — unguarded, this runs until it hits a governor limit (typically "Too many DML statements" or "Apex CPU time limit exceeded"), crashing the transaction.
Guarding with a static flag
public class AccountTriggerHandler {
private static Boolean hasRun = false;
public void afterUpdate(List<Account> updatedAccounts) {
if (hasRun) {
return;
}
hasRun = true;
for (Account acc : updatedAccounts) {
acc.Description = 'Last updated: ' + System.now();
}
update updatedAccounts;
}
}
public class AccountTriggerHandler {— the handler class.private static Boolean hasRun = false;— this is Module 10'sstaticfields — one shared value per class, not per object — put to direct use.- (blank line)
public void afterUpdate(List<Account> updatedAccounts) {— the method.if (hasRun) {— checks the guard first.return;—hasRunpersists across the recursive re-entry within the same transaction, so the second (recursive) call seeshasRun == trueand exits immediately.}— closes theif.hasRun = true;— marks that this logic has now run.- (blank line)
for (Account acc : updatedAccounts) {— the same loop as before.acc.Description = 'Last updated: ' + System.now();— the same change.}— closes the loop.update updatedAccounts;— this update fires the trigger again, but the guard clause above stops it from updating and re-triggering a second time.}— closes the method.}— closes the class.
Recognizing the symptoms
An unguarded recursive trigger typically shows up as a governor limit error — often "Too many DML statements" or "Apex CPU time limit exceeded" — from what looks like a single, simple update. If a trigger's error message mentions far more DML operations than the actual number of records being saved, unguarded recursion (rather than the SOQL/DML-in-a-loop problems from Module 7) is a strong suspect worth checking first.
Exercise
Add a static recursion guard to this handler method so it only runs its logic once per transaction.
Show hint
private static Boolean hasRun = false; then check and set it at the top of the method.
Trigger Recursion Quiz
My Notes
Log in to keep private notes on this lesson.
Questions about this lesson
No questions yet — be the first to ask.
Log in to ask a question about this lesson.
Summary
A trigger that performs DML on its own object can accidentally trigger itself again — trigger recursion — and needs a guard to stop it from running out of control.