1

Can someone point me in the direction of not getting the error

OpportunityTrigger: execution of AfterUpdate caused by: System.FinalException: SObject row does not allow errors: Trigger.OpportunityTrigger: line 34, column 1

trigger OpportunityTrigger on Opportunity (after delete, after insert, after undelete, after update, before delete, before insert, before update) {
    try {
        map<Id, Opportunity> sendVOCS = new map<Id, Opportunity>();
        map<id, Opportunity> stageChanged = new map<Id, Opportunity>();

        if (trigger.isAfter) {
            system.debug('OpportunityTrigger isAfter');
            if (trigger.isUpdate) {
                system.debug('OpportunityTrigger isAfter isUpdate');
                for (Opportunity record : trigger.newMap.Values()) {
                    Opportunity oldMapMatch = trigger.oldMap.get(record.Id);
                    if (record.StageName != oldMapMatch.StageName) {
                        // Voice of Customer Survey criteria
                        if (record.StageName == 'Closed - Awarded' || record.StageName == 'Closed - Lost') {
                            sendVOCS.put(record.Id, record);
                        }
                        // add newMap opportunity to a id/opp map
                        stageChanged.put(record.Id, record);
                    }
                }
                // send voice of customer surveys if they should be - criteria is above
                if (sendVOCS.keySet().Size() > 0) {
                    SendMail sendMail = new SendMail();
                    sendMail.SendVoiceOfCustomerSurvey(sendVOCS);
                    system.debug('Send Voice of Customer Surveys');
                }
                if (stageChanged.keySet().Size() > 0) {
                    StatusAndStageLogging statusAndStageLogging = new StatusAndStageLogging();
                    statusAndStageLogging.logOpportunityStage(stageChanged, trigger.oldMap);
                    system.debug('Log Opportunity Stage');
                }

                for (Opportunity opp : trigger.old){
                    opp.addError ('Opportunities can not be deleted');
                }
            }
        }
    }
    catch (exception e){
        ErrorHandler error = new ErrorHandler();
        error.logError(e);
    }
}
1

You are getting this error because of this below lines

for (Opportunity opp : trigger.old){ 
    opp.addError ('Opportunities can not be deleted'); 
}

Triggers can be used to prevent DML operations from occurring by calling the addError() method on a record or field. When used on Trigger.new records in insert and update triggers, and on Trigger.old records in delete triggers, the custom error message is displayed in the application interface and logged. More help i.e. Trigger Exceptions on this link.

You cannot use Trigger.Old to addError in After Update context.

You will have to surround that code of yours by checking the condition so that it runs only in before delete context. You will have to remove the above code from Trigger.IsUpdate and Trigger.isAfter condition and add a separate condition.

if(Trigger.IsDelete && Trigger.IsBefore){
    for (Opportunity opp : trigger.old){ 
        opp.addError ('Opportunities can not be deleted'); 
    }
}

It is always a best practice to check in which context your particular code should execute.

4

You're adding the error on the wrong sObject in after update context. From Trigger Exceptions:

Triggers can be used to prevent DML operations from occurring by calling the addError() method on a record or field. When used on Trigger.new records in insert and update triggers, and on Trigger.old records in delete triggers, the custom error message is displayed in the application interface and logged.

Emphasis is mine.

It looks like your trigger is simply missing some logic. This code

            for (Opportunity opp : trigger.old){
                opp.addError ('Opportunities can not be deleted');
            }

should be running in a delete context, but you have it running on update. Adopting a trigger handler pattern and delegating this functionality to a handler class will help you maintain what actions need to take place in which contexts.

  • 1
    Or at least move up to switch statements. There's no real reason to continue using the nested-if pattern in modern code. – sfdcfox Feb 26 at 17:04

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.