System.FinalException: Record is read-only: Trigger.updateCompetitors: line 24

I am writing a trigger to get all the Opportunity competitors into a field on Opportunity, however, getting an error while testing it.

Error: updateCompetitors: execution of AfterUpdate caused by: System.FinalException: Record is read-only: Trigger.updateCompetitors: line 24

Can you please check the below code and suggest me what’s wrong with this?

trigger updateCompetitors on Opportunity(after insert, after update){
   List<Opportunity> OppIds = new List<Opportunity>();
    for (Opportunity opp:{
 List<OpportunityCompetitor> oppComps = new List<OpportunityCompetitor>();
 oppComps= [select id, CompetitorName, Strengths, Weaknesses from OpportunityCompetitor where OpportunityId in: Trigger.newMap.keySet()];
 List<Opportunity> OppstoUpdate = new List<Opportunity>();

 for (Opportunity opp: OppIds){
    String allcomps = null;
     if( oppComps.size()>0 ) {
      for (integer i = 0; i < oppComps.size(); i++){
         allcomps = allcomps + oppComps[i].CompetitorName+',';
   opp.OpportunityCompetitors__c = allcomps;

  update OppstoUpdate;


This is because you are in an after insert/update trigger and the records are read only in that context as they have been written, but not committed, to the database.

Unfortunately your trigger is relying on the ids of the records, which means you won’t be able to use before insert as the ids won’t be populated at that time (as the records haven’t been written to the database at that point so while you can write to them, database generated fields aren’t populated).

In this instance you’ll need to clone the record (or query anew via SOQL) and make changes to the new copy of the record, then execute the update against the new copies.

Source : Link , Question Author : user5208 , Answer Author : Bob Buzzard

Leave a Comment