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, 2014 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, 2014 at 9:16

1 Answer 1


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, 2014 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, 2014 at 8:20
  • Have updated the question
    – user7831
    Apr 11, 2014 at 8:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .