I'm learning the APEX world (coming from the .NET world).

Defined a custom exception.

In a method (say A()) i'm using a try catch block in which, i 'm calling another method of another class (say Classname2.B() ).

In this Classname2.B() i 'm throwing the public defined Exception.

This does not get caught!!

If instead i throw the exception in the try catch block, then the exception gets caught! What do i miss? Shouldn't this work also in APEX (like in the .NET world)?

public class SomeClass {
    public void A() {
        try {
            Classname.B(); //<- doesn't work
            throw new CustomException();//<-works
        catch(CustomException ex) {}

public class Classname {
    void B() {
        throw new CustomException();

EDIT: Here is the actual code (which is stripped down to only the relevant parts).

The trigger looks like this:

trigger Expenses on Expense__c (before insert, before update) {
    if(Trigger.isBefore && (Trigger.isUpdate  || Trigger.isInsert)) {
        Travel__c travel = getTravel(); 
        ExpensesTriggerHandler.onBeforeInsertOrUpdate(trigger.new, travel);

The ExpensesTriggerHandler looks like this:

public with sharing class ExpensesTriggerHandler {

    public static void onBeforeInsertOrUpdate(List<Expense__c> newExpenses, Travel__c travel) {
        ExpenseValidator.validate(newExpenses, travel);


The ExpenseValidator looks like this:

public with sharing class ExpenseValidator {

    private static List<ExpenseRule> rules;

    static {
        rules = new List<ExpenseRule>();

        for(ApexClass clazz : [SELECT NamespacePrefix, Name FROM ApexClass WHERE isValid = true]) {
            Type t = Type.forName(clazz.NamespacePrefix, clazz.Name);

            try {
                ExpenseRule rule = (ExpenseRule) t.newInstance();
            catch(Exception ignored) {}

    public static void validate(List<Expense__c> expenses, Travel__c travel) {

        for(ExpenseRule rule : rules) {

            for(Expense__c expense : expenses) {


One of the classes implementing the ExpenseRule Interface is the following (from which the exception gets thrown):

public with sharing class ExpenseCannotEndBeforeStartRule implements ExpenseRule {

    private final static String ERROR_MESSAGE = 'Expense begins after end.';

    public void validate(Expense__c expense) {
        if (expense.dtm_DepartureTime__c > expense.dtm_ArrivalTime__c){
            throw new ExpenseValidationException(ERROR_MESSAGE);

  • Now that you've added your actual code (although stripped down), is there any reason why this is not implemented as a validation rule? Apr 11 '14 at 9:04
  • We have multiple classes implementing this Interface. So we simply create a new one and it is available as a validation rule.
    – user7831
    Apr 11 '14 at 9:16

It should work exactly as in .NET, you should be able to catch any exception besides limit and fatal exceptions. I tried to reproduce your scenario and it behaves as I'd expect.

public class Exceptions{
      public class TestException extends Exception{}

public class testRND{
     //your Classname.B method
     public static void throwException(){
          throw new Exceptions.TestException('test..');

public class testRND_two{
      //your Someclass.A method
      public void replicateExceptionQ(){


                 throw new Exceptions.TestException('blablabla');
           }catch(Exceptions.TestException x){
                System.debug('----------------------->CAUGHT:' +x.getMessage());

Executing this anonymously you'll see that it DOES get caught:

testRND_two test= new testRND_two();

Execute Anonymous: testRND_two test= new testRND_two();
Execute Anonymous: 
Execute Anonymous: test.replicateExceptionQ();
08:58:00.092 (92865804)|EXECUTION_STARTED
08:58:00.092 (92872955)|CODE_UNIT_STARTED|[EXTERNAL]|execute_anonymous_apex
08:58:00.096 (96210154)|METHOD_ENTRY|[1]|01pd0000002dWBM|testRND_two.testRND_two()
08:58:00.096 (96218290)|METHOD_EXIT|[1]|testRND_two
08:58:00.096 (96301071)|CONSTRUCTOR_ENTRY|[1]|01pd0000002dWBM|<init>()
08:58:00.096 (96342058)|CONSTRUCTOR_EXIT|[1]|01pd0000002dWBM|<init>()
08:58:00.096 (96391101)|METHOD_ENTRY|[3]|01pd0000002dWBM|sdry.testRND_two.replicateExceptionQ()
08:58:00.096 (96437928)|ENTERING_MANAGED_PKG|
08:58:00.096 (96460150)|USER_DEBUG|[8]|DEBUG|------------>SC1
08:58:00.097 (97902331)|METHOD_ENTRY|[1]|01pd0000002dWBH|testRND.testRND()
08:58:00.097 (97909789)|METHOD_EXIT|[1]|testRND
08:58:00.097 (97924747)|CONSTRUCTOR_ENTRY|[9]|01pd0000002dWBH|<init>()
08:58:00.097 (97942555)|CONSTRUCTOR_EXIT|[9]|01pd0000002dWBH|<init>()
08:58:00.097 (97961441)|METHOD_ENTRY|[10]|01pd0000002dWBH|sdry.testRND.throwException()
08:58:00.099 (99666391)|CONSTRUCTOR_ENTRY|[5]|01pd0000002dWBC|<init>(String)
08:58:00.100 (100284398)|CONSTRUCTOR_EXIT|[5]|01pd0000002dWBC|<init>(String)
08:58:00.100 (100324604)|EXCEPTION_THROWN|[5]|sdry.Exceptions.TestException: test..
08:58:00.100 (100332154)|METHOD_EXIT|[10]|01pd0000002dWBH|sdry.testRND.throwException()
08:58:00.100 (100377232)|ENTERING_MANAGED_PKG|
08:58:00.100 (100388207)|USER_DEBUG|[20]|DEBUG|----------------------->CAUGHT:test..
  • OK i see! Is it than may be due to the fact that method A() is called in a trigger? Are there any limitations?
    – user7831
    Apr 11 '14 at 8:17
  • To my knowledge that shouldn't matter. This IS about a custom exception right ? Maybe posting your simplified real code can shed more light on the matter. Apr 11 '14 at 8:20
  • Have updated the question
    – user7831
    Apr 11 '14 at 8:56

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.