+ Start a Discussion
apsullivanapsullivan 

Conflicting Trigger Exception "Cannot Recursively Update Itself"

I'm new to development and I've written a trigger to update the Account with a field when a) the field is blank and b) a Contact is created or updated and contains a value in a corresponding field.  The idea being to maintain the data in two places.  However, I'm getting an exception which references "kugadd" which I assume is from the Kugamon package we have installed.  Can anyone help?

 

Here is my trigger:

 

trigger OnAccountContactCategory on Contact (before insert, before update) {

    List<Id> AccountsToUpdate = new List<Id>{}; 
    // Find account to update
    for(Contact c: Trigger.new){
        if (c.Categorycontact__c != Null && c.AccountId != Null)  {
              AccountsToUpdate.add(c.AccountId);
        }
        // Pull field data from account
      List<Account> accts = new List<Account>([SELECT Id, Category__c FROM Account WHERE Id IN :AccountsToUpdate]);
        // Update account    
      for(Account a: accts) {
         if (a.Category__c == Null) {
                a.Category__c = c.Categorycontact__c;
              update a;
         }
      }
   }
}

 

Here is the emailed exception (I removed the IDs themselves):

 

 

OnAccountContactCategory: execution of BeforeUpdate

caused by: System.DmlException: Update failed. First exception on row 0 with id [ACCOUNT ID]; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, kugadd.AccountAfterInsertAfterUpdate: execution of AfterUpdate

caused by: System.DmlException: Update failed. First exception on row 0 with id [CONTACT ID]; first error: SELF_REFERENCE_FROM_TRIGGER, Object (id = [CONTACT ID]) is currently in trigger OnAccountContactCategory, therefore it cannot recursively update itself: []

(kugadd)
: []

Trigger.OnAccountContactCategory: line 15, column 1

 

Thoughts?  Thanks!

Neetu BansalNeetu Bansal
Hi,

Try this:

trigger OnAccountContactCategory on Contact (before insert, before update) {

Set<Id> AccountsToUpdate = new Set<Id>{};
// Find account to update
for(Contact c: Trigger.new){
if (c.Categorycontact__c != Null && c.AccountId != Null) {
AccountsToUpdate.add(c.AccountId);
}
}

// Pull field data from account
List<Account> accts = new List<Account>([SELECT Id, Category__c FROM Account WHERE Id IN :AccountsToUpdate]);
List<Account> accountUpdateList = new List<Account>();
// Update account
for(Account a: accts) {
if (a.Category__c == Null) {
a.Category__c = c.Categorycontact__c;
accountUpdateList.add(a);
}
}
if(accountUpdateList.size() > 0)
update accountUpdateList;
}

Please mark this as solution if you are able to solve your problem, so it might would help others too.

Thanks,
Neetu Bansal

Bhawani SharmaBhawani Sharma
Do you have any trigger on Account object also?
apsullivanapsullivan

Hi Neetu,

 

First of all thank you for taking the time out to help!  I was getting an error "Variable c.Categorycontact__c does not exist" which appeared on line 17. I was able to resolve this by moving braces around, and the trigger appears to be working as expected when I manually cause it, which my prior code did, as well.

 

I'm realizing now, also, that it looks like what throws this exception is an action taken by Kugamon I believe.  I may have to dig a bit deeper.  It looks like the Kugamon action is what causes the exception, though.

 

Here is your code with changes mentioned, also:

 

trigger OnAccountContactCategory on Contact (before insert, before update) {

Set<Id> AccountsToUpdate = new Set<Id>{};
// Find account to update
for(Contact c: Trigger.new){
if (c.Categorycontact__c != Null && c.AccountId != Null) {
AccountsToUpdate.add(c.AccountId);
}

// Pull field data from account
List<Account> accts = new List<Account>([SELECT Id, Category__c FROM Account WHERE Id IN :AccountsToUpdate]);
List<Account> accountUpdateList = new List<Account>();
// Update account
for(Account a: accts) {

if (a.Category__c == Null) {
a.Category__c = c.Categorycontact__c;
accountUpdateList.add(a);
}
}
if(accountUpdateList.size() > 0)
update accountUpdateList;
}
}
apsullivanapsullivan
Hi Tech Force,

I don't believe there are any custom triggers on the account object, but there may be a manager trigger on it. Could it be that the Kugamon Account/Contact Sync package is attempting to update the account at the same time that my trigger is? Would that cause a conflict?

Alex
Bhawani SharmaBhawani Sharma
Probably that can be a cause. I would suggest to use a static flag. What you need to do is, create a static flg in any helper class like
public static Boolean EXECUTE_OnAccountContactCategory_TRIGGER = true;

Default value for thsi will be always true. In end of your trigger, you can set it as false before updating the account. So it will stop the recusive execution.

trigger {
if(Helper.EXECUTE_OnAccountContactCategory_TRIGGER == true) {
//youe logic
Helper.EXECUTE_OnAccountContactCategory_TRIGGER = false;
update a;
}
}
DipakDipak

yes, Same thing is decsribed in above blog links

Ex: 

public class FutureUpdateController{
 
    public static boolean isFutureUpdate = false;
 
}-----------------------

rigger updateSomething on Account (after insert, after update) {
 
    //execute
    if(FutureUpdateController.isFutureUpdate != true){
        
         //Do some thing / your logic
        }
         //your logic
FutureUpdateController.isFutureUpdate=true
     }
}
apsullivanapsullivan

Thanks to everyone for the help.  Following the instructions in the Mindfire blog post from Dipak, I've added the additional classes to circumvent the recursive update.  First of all, does this look correct?  If not, should I be removing from my trigger the "update" portion (bolded below)?  I'm wondering if I can actually just revert to my original class from the first post except with the FutureUpdateController condition since the extra layers added initially did not resolve the issue.

 

Here's where I am at now:

 

Trigger:

 

trigger OnAccountContactCategory on Contact (before insert, before update) {

if(FutureUpdateController.isFutureUpdate != true){

    Set<Id> AccountsToUpdate = new Set<Id>{};
	// Find account to update
	for(Contact c: Trigger.new){
		if (c.Categorycontact__c != Null && c.AccountId != Null) {
		AccountsToUpdate.add(c.AccountId);
		}

	// Pull field data from account
	List<Account> accts = new List<Account>([SELECT Id, Category__c FROM Account WHERE Id IN :AccountsToUpdate]);
	List<Account> accountUpdateList = new List<Account>();
	// Update account
	for(Account a: accts) {
		if (a.Category__c == Null) {
		a.Category__c = c.Categorycontact__c;
		accountUpdateList.add(a);
		}
	}
	if(accountUpdateList.size() > 0)
	update accountUpdateList;
    
//Send Ids to @future method for processing FutureMethodsProcessor.processAccounts(AccountsToUpdate); } } }

 

Future Update Controller class:

 

public class FutureUpdateController{
	    public static boolean isFutureUpdate = false;
}

 

Future Methods Processor class:

 

public class FutureMethodsProcessor{
    @future
    public static void processAccounts(Set<Id> IDs){

         // list to store the accounts to update
          List<Account> accountsToUpdate = new List<Account>();
         
          // iterate through the list of accounts to process
          for (Account a : [Select Id, Category__c From Account where ID IN :IDs]) {
               
               // add the account to the list to update
               accountsToUpdate.add(a);
          }

        //Before we perform this update we want to set the isFutureUpdate boolean in our utility class   to true 
       
        FutureUpdateController.isFutureUpdate = true;
         //Now we can perform the update. The trigger will still fire but none of the code inside of it will execute 
        update accountsToUpdate;

    }
}

Thanks again for the help!!

Bhawani SharmaBhawani Sharma
Do you really need to use future method. I think, you can remove @future annototation to get data updated in real time
apsullivanapsullivan
Bhawani,

Won't that just land me back in the same spot where conflicts are occurring? By the way, on my sandbox environment, that code is working as expected, which satisfies sort of the core requirement, but whether it circumvents the exception when the Kugamon action executes is yet to be determined.