5

Is there a way to calculate if an SObject in a trigger context has had an error added to it (either with addError or through a validation rule)?

I have some trigger processes I don't want to run if we don't end up inserting/updating this sobject.

4

I don't think there is a direct method for determining if an sObject has errors on it. There might be a method to tell, but I would rely on the triggers order of operations here. Any DML operations will fail if there's an added error, so by running those processes in an after trigger context will ensure that the record survived the initial process without getting an error added.


Looks like ApexPages.HasMessages() will return true in a trigger context! Not only that, but the severity parameters will return accurate information. ApexPages.GetMessages() will even go as far as to return the actual messages added, despite there being no page associated with the trigger.

Execute Anon Snippet:

insert new Account(Name = 'Test'); 

Trigger (Set up to fail & print message info)

trigger TestTrigger on Account (before insert) {

    for (Account a:trigger.new) {
        a.Name.AddError('Forced Failure');
    }

    System.debug(ApexPages.hasMessages()); // true 
    System.debug(ApexPages.hasMessages(ApexPages.Severity.ERROR)); // true 

    for (ApexPages.Message message:ApexPages.getMessages()) {
        System.debug(message.getComponentLabel()); // Account Name 
        System.debug(message.getDetail()); // Forced Failure 
        System.debug(message.getSeverity()); // Error 
        System.debug(message.getSummary()); // Forced Failure 
    }
}

All the methods of ApexPages.Message return useful information, but since the Message class was designed to work with standard visualforce pages, which have only a single record related to that page, they don't seem to store the id of the record with the message, which is a problem for determining which records have failed.

Theres a constructor to create a Message with an Id, but it looks like its meant for a visualforce element id, not a record id, and theres still no easy way to get that value..

| improve this answer | |
  • Wow! What a discovery! It doesn't address the problem since some records may pass and some may fail, but this is very useful information – Charles Koppelman Jan 24 '18 at 19:18
  • 1
    At the very least, this lets you do if (!ApexPages.HasMessages(ApexPages.Severity.ERROR)) { //.. } to control entering expensive calls. . – battery.cord Jan 24 '18 at 19:21
  • Also note that there isn't a way to clear page messages once added, so once added, you're stuck with them for the rest of the transaction (again, tying in to how this is really meant for Visualforce). – Derek F Jan 24 '18 at 19:25
  • You can kind of use messages to report errors with ids, by calling something like ApexPages.AddMessage(new ApexPages.Message(Severity, 'Error Info', 'Details', 'RecordId')); instead of using sObject.addError, but since you can't do sObject.Field.AddError(new ApexPages.Message) its kind of pointless - you might as well write your own error handling framework instead of trying to force messages to work outside of their intended context. Even if there were ids available through messages, not all trigger records will have an id, so it only kind of helps. – battery.cord Jan 24 '18 at 19:39
  • Getting error: ApexPages.hasMessages can only be called from a Visualforce page – Aequitas Jul 27 '18 at 7:10
2

As of Winter '21, there is a method called hasErrors() on SObjects (ref). The way to solve this problem now is to call:

Account acct = new Account();
// doSomething to acct;
if (!acct.hasErrors()) {
  // do something
}
| improve this answer | |

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.