+ Start a Discussion
JJamesJJames 

Problem updating custom field in Apex Trigger

I am getting an error when i run the trigger shown below.  The error I get is:
"Error:Apex trigger acctTeamUpdate caused an unexpected exception, contact your administrator: acctTeamUpdate: execution of AfterUpdate caused by: System.FinalException: Record is read-only: Trigger.acctTeamUpdate: line 23, column 1" 

and my trigger:
 
trigger acctTeamUpdate on Account (after update, after insert) {
    for (Account a : Trigger.new)
    {

        Territory__c t;
    
        try {                                                    // get the Territory record for the territory specified in the Account Record
            t = [SELECT ID, Name, ASD_Sales_Rep__c, PSD_Sales_Rep__c, Service_Sales_Rep__c, Switch_Sales_Rep__c, Transmission_Sales_Rep__c, Rep_Agency__c
                FROM Territory__c
                WHERE ID=:a.Territory__c LIMIT 1];
        }
        catch(exception ex){ 
            System.debug(' Failed Territory Record Retrieval');
        }
        if(Trigger.isInsert)
        {
            
        }
        if(Trigger.isUpdate)
        {
            try
            {
                a.Rep_Agency__c = t.Rep_Agency__c;
                
            }
            catch(exception ex)
            { 
                System.debug(' Failed Account Update');
            }
        }
    }
}

it says that the
a.Rep_Agency__c field is read only?  And the Rep_Agency__c field is of type Lookup(Account)
Any idea why I might be getting this error?

Thanks.
Shyama B SShyama B S
Can you try changing the trigger to before update and before insert? The records become read-only in the after triggers. 
Ketankumar PatelKetankumar Patel
Hi James, you can not update account records in its after insert or after update trigger call. This is not allowed. A runtime error is thrown, as trigger.new is already saved.

You should store it in a list or map and then at end of your trigger loop you can update that list. 

Please try below code and let me know if you get any errors. 
trigger acctTeamUpdate on Account (after update, after insert) {
    List<Account> accUpdateList = new List<Account>();
	for (Account a : Trigger.new)
    {
       Account acc = new Account();
	   
        Territory__c t;
    
        try {                                                    // get the Territory record for the territory specified in the Account Record
            t = [SELECT ID, Name, ASD_Sales_Rep__c, PSD_Sales_Rep__c, Service_Sales_Rep__c, Switch_Sales_Rep__c, Transmission_Sales_Rep__c, Rep_Agency__c
                FROM Territory__c
                WHERE ID=:a.Territory__c LIMIT 1];
        }
        catch(exception ex){ 
            System.debug(' Failed Territory Record Retrieval');
        }
        if(Trigger.isInsert)
        {
            
        }
        if(Trigger.isUpdate)
        {
                acc.Rep_Agency__c = t.Rep_Agency__c;
				acc.Id = a.Id;
				accUpdateList.add(acc);
        }
    }
	
	try{
		update accUpdateList;
	}
	catch(exception ex)
            { 
                System.debug(' Failed Account Update');
            }
}

You should read this : Click Here (https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_context_variables_considerations.htm)
Pramodh KumarPramodh Kumar
First rule while writing trigger, Bulkify

Here is the sample code for scenario and let me know if you still have any issue.
trigger acctTeamUpdate on Account (after update, after insert) {
    
    list<id> accIds = new list<id>();
    list<id> tIds = new list<id>();
    if(Trigger.isInsert){
        for (Account a : Trigger.new)
        {
           accIds.add(a.id);
            tIds.add(a.Territory__c );
            
        }
    }
    if(Trigger.isUpdate){
        for (Account a : Trigger.new)
        {
           accIds.add(a.id);
            tIds.add(a.Territory__c );
        }
    }
    map<id,Territory__c > accUpdateMap = new map<id,Territory__c >([select id,Rep_Agency__cfrom Territory__c where id iN: tIds]);
    list<account> updateAcc = new list<account>();
    
    for(account ad : [select id,Rep_Agency__c,Territory__c from account where id IN: accIds]){
        if(ad.Rep_Agency__c==null){
            ad.Rep_Agency__c= accUpdateMap.get(ad.Complaint__c).Rep_Agency__c;
            updateAcc.add(ad);
        }
    }  
    update updateAcc;
}
Thanks,
Pramodh
 
JJamesJJames
Thank you guys for your input.  I tried each method but the rep agency still is not populating after updating the territory on an account for some reason.  They did not throw any errors either.
And on the last solution from Pramodh, you put ad.Compliant__c , should this be ad.id instead?
Pramodh KumarPramodh Kumar
Sorry it's ad.territory__c. I was testing with my objects before sending the code. Replace and try it. It will work
JJamesJJames
Pramodh,

That's what I suspected, I tried that and it looks like it may be getting stuck in a recursive state as I get the error:

Error:Apex trigger acctTeamUpdate caused an unexpected exception, contact your administrator: acctTeamUpdate: execution of AfterUpdate caused by: System.DmlException: Update failed. First exception on row 0 with id 001Z0000015o4SbIAI; first error: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY, acctTeamUpdate: maximum trigger depth exceeded Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb] Account trigger event AfterUpdate for [001Z0000015o4Sb]: []: Trigger.acctTeamUpdate: line 30, column 1
Ketankumar PatelKetankumar Patel
Hi James, you are facing Recursive trigger issue and in my code I am updating in try catch  batch that is why you don't see error on record page you should see error in debug log if you set one up for your self.

Here is the solution. Create another class having static boolean variable and static method so you can call from your trigger. 

salesforce solution for recursive trigger : https://help.salesforce.com/apex/HTViewSolution?id=000133752&language=en_US (https://help.salesforce.com/apex/HTViewSolution?id=000133752&language=en_US)
 
public Class checkRecursive{
    private static boolean run = true;
    public static boolean runOnce(){
    if(run){
     run=false;
     return true;
    }else{
        return run;
    }
    }
}
 
trigger acctTeamUpdate on Account (after update, after insert) {

if(checkRecursive.runOnce()){

    List<Account> accUpdateList = new List<Account>();
	for (Account a : Trigger.new)
    {
       Account acc = new Account();
	   
        Territory__c t;
    
        try {                                                    // get the Territory record for the territory specified in the Account Record
            t = [SELECT ID, Name, ASD_Sales_Rep__c, PSD_Sales_Rep__c, Service_Sales_Rep__c, Switch_Sales_Rep__c, Transmission_Sales_Rep__c, Rep_Agency__c
                FROM Territory__c
                WHERE ID=:a.Territory__c LIMIT 1];
        }
        catch(exception ex){ 
            System.debug(' Failed Territory Record Retrieval');
        }
        if(Trigger.isInsert)
        {
            
        }
        if(Trigger.isUpdate)
        {
                acc.Rep_Agency__c = t.Rep_Agency__c;
				acc.Id = a.Id;
				accUpdateList.add(acc);
        }
    }
	
	try{
		update accUpdateList;
	}
	catch(exception ex)
            { 
                System.debug(' Failed Account Update');
            }
   }
}

Let me know if you get any issues. 
Pramodh KumarPramodh Kumar
Hi James,

Sorry for all the error, I didnt think about the recurrsive Trigger when writing the code.

Here the Code for your scenario. It will also give ability to insert/update the data in bulk. Please try to buliky your code when ever you trying to insert/update/delete. This will help you to write code more consistent way without hitting the governor limits

Please let me know if you still face any issue.
public class staticVariable {
    public static boolean AccountTrigger = true;
}

//Tirgger Starts from here
trigger acctTeamUpdate on Account (after update, after insert) {
    
    list<id> accIds = new list<id>();
    list<id> tIds = new list<id>();
if(staticVariable.AccountTrigger){
    staticVariable.AccountTrigger = false;
    if(Trigger.isInsert){
        for (Account a : Trigger.new)
        {
           accIds.add(a.id);
            tIds.add(a.Territory__c );
            
        }
    }
    if(Trigger.isUpdate){
        for (Account a : Trigger.new)
        {
           accIds.add(a.id);
            tIds.add(a.Territory__c );
        }
    }
    map<id,Territory__c > accUpdateMap = new map<id,Territory__c >([select id,Rep_Agency__cfrom Territory__c where id iN: tIds]);
    list<account> updateAcc = new list<account>();
    
    for(account ad : [select id,Rep_Agency__c,Territory__c from account where id IN: accIds]){       
            ad.Rep_Agency__c= accUpdateMap.get(ad.Territory__c).Rep_Agency__c;
            updateAcc.add(ad);
    }
    if(!updateAcc.isEmpty())
         update updateAcc;
}
}

Thanks,
Pramodh