Skip to main content

Error Handling and Debugging in Apex

About Us
Published by JET BI
20 November 2024
28

Error Handling and Debugging in Apex: Tips for Troubleshooting Effectively


Introduction

Salesforce developers working with Apex often face complex error scenarios and debugging challenges. This article delves into practical techniques and strategies for troubleshooting issues in Apex development.

Error Handling Techniques in Apex

Error handling techniques help to create a controlled and informative response to errors which is extremely important in Salesforce development.

Try-Catch-Finally Blocks

Apex’s try-catch construct is the foundation of error handling. It allows us to isolate risky code and manage exceptions when they appear. If an exception is thrown, it is caught and code in the catch block is executed. Finally block executes regardless of whether the operation succeeded or failed, ensuring any final tasks or resource cleanups are handled.

try {
    Account acc = new Account(Name = null); // This will cause a required field error
    insert acc; 
  System.debug('Statement after insert.'); // This does not execute because insert causes an exception
} catch (DmlException e) {  
    System.debug('The following exception has occurred: ' + e.getMessage());  
} finally {  
    System.debug('Execution completed. Performing cleanup if needed.');  
}

In this snippet, the try block contains the potentially error-prone operation, while the catch block captures and handles the DmlException. Without this structure, the entire transaction would fail. If you are interested in a more detailed explanation, please check the following  Apex Developer Guide that provides Exception Handling Example step by step.

Using Exception Methods

Apex exceptions provide built-in methods to retrieve detailed information about errors, making them invaluable for debugging and error resolution. These methods can be called on exception instances to extract specific details.

Common Exception Methods:

  • getMessage() - can be used to obtain the error message to be displayed to the user.
  • getTypeName() - returns the type of exception (e.g., DmlException, NullPointerException).
  • getLineNumber() - returns the line number of the exception.
  • getCause() - returns the cause of the exception as an exception object (if available).
try {  
    Account acc = new Account(Name = null);  
    insert acc;  
} catch (DmlException e) {  
    System.debug('Error message: ' + e.getMessage());  
    System.debug('Error type: ' + e.getTypeName());  
    System.debug('Error at line: ' + e.getLineNumber());  
    System.debug('Cause of the error: ' + e.getCause());  
}

Combining these methods allows developers to generate detailed logs and improve error reporting so it is easier to catch and solve an issue. 

Throwing Custom Exceptions

Default error messages are often too technical for end-users. We can provide user-friendly messages to enhance the overall experience. Custom exceptions are capable of specifying detailed error messages and have additional custom error handling in catch blocks.

catch (DmlException e) {  

    throw new CustomException('Oops! Unable to process your request. Please check the input values.');  

}

Here, a custom exception replaces the generic DmlException message, making it easier for users to understand the issue.

Common Exceptions

The most common exceptions are DML Exceptions, Null Pointer Exceptions and Query Exceptions. Let’s see what are these exceptions and how we can handle them properly.

  • DMLExceptions: can be any problem with a DML statement, usually the result of a required field not being set. Wrap DML operations in try-catch blocks and use Database.saveResult to track operation success or failure.
  • NullPointerExceptions: can be any problem with dereferencing a null variable. Always check if an object is null before accessing its properties or methods.
if (myObject != null) {  
    System.debug(myObject.Name);  
} else {  
    System.debug('Object is null');  
}
  • QueryExceptions: can be any problem with SOQL queries, such as assigning a query that returns no records or more than one record to a singleton sObject variable. Use a safe approach like List queries to avoid unhandled QueryException errors.
List<Contact> contacts = [SELECT Id, Name FROM Contact WHERE Email = :email LIMIT 1];  

if (!contacts.isEmpty()) {  
    System.debug(contacts[0].Name);  
} else {  
    System.debug('No contact found');  
}

 

Debugging Tools and Techniques in Salesforce

Salesforce provides a lot of tools to help developers debug their code efficiently. That is why understanding when and how to use these tools is key to solving problems quickly.

  • Debug Logs capture database operations, system processes, and errors that occur when executing a transaction or running unit tests. Can be enabled in Setup. Includes setting Log Level that helps to avoid unnecessary noise. It is recommended to use filters and search for keywords to pinpoint the root cause.

If you are interested in more detailed information about Debug Logs, check this Apex Developer Guide

  • System.debug() Statement is often the first line of defense in understanding code behavior. It is recommended to include clear context, such as variable values and execution flow, and use log categories (e.g., "INFO: Value of x is:") for better organization.
  • Checkpoints in Developer Console can be added to specific lines in an Apex source code to provide additional information related to the lines. 

 

Conclusion

Developers can streamline their troubleshooting process and deliver reliable applications by using try-catch-finally blocks, employing user-friendly error messages and mastering Salesforce's debugging tools.  Adopting best practices not only simplifies development but also ensures a better experience for end-users which is extremely important. 

Stay informed and elevate your Salesforce skills by exploring our blog for more in-depth tutorials, tips, and expert advice.


Anzhelika Makarova
Junior Salesforce Developer
image
Expertise
Question to the expert
image

We have available resources to start working on your project within 5 business days

1 UX Designer

image

1 Admin

image

2 QA engineers

image

1 Consultant

image
Related Articles
All articles
image
Is Salesforce Winning the Public Sector Race?
An analysis of Salesforce's rapid expansion into the U.S. public sector, tracing its path from cautious early government licensing deals in the 2010s through the launch of Government Cloud in 2012, its pivotal role in COVID-19 vaccine rollouts, and its 2025–2026 push into military and intelligence work via Agentforce and Missionforce. The piece covers major 2026 contracts — including a $5.6 billion Army deal, a $1.6 billion VA agreement, and Pentagon Impact Level 5 authorization — alongside real-world case studies like California's REAL ID processing and the UK's NHS back-office operations. It also examines the structural obstacles still facing Salesforce and other vendors in government tech: legacy IT systems decades old, outdated federal procurement rules, budget constraints, and organizational caution around AI adoption, plus the competitive pressure from Palantir, Microsoft, and Oracle in the race for public sector AI spending.
28 August 2026
image
Why Your Salesforce Flows Are Agentforce's Biggest Problem
This article argues that the most underestimated risk in Agentforce deployments isn't data quality — it's the automation layer: years of overlapping Flows, Process Builder processes, Apex triggers, and managed package logic that no one has reviewed end-to-end. It explains why AI agents inherit automation complexity without the tribal knowledge human admins carry, why technical debt only becomes visible after an agent hits it in production, and why a clean demo is no indicator of production readiness. The article closes with a concrete, tool-by-tool inventory approach using Flow Trigger Explorer, Salesforce Optimizer, Setup Audit Trail, Apex Debug Logs, Agent Builder, and Health Check — scoped to the specific processes the agent will actually use rather than the whole org.
23 July 2026
image
How to Wire Multiple Salesforce Projects in One Org Without Breaking Everything
This article maps the real integration patterns that emerge when multiple Salesforce projects — both managed packages and unpackaged code — share a single org. It covers four concrete patterns: attaching custom triggers to package-owned objects, calling global members exposed by managed packages, writing directly into another project's objects, and runtime-guarded reads of package data. It then addresses access control for authenticated and guest users, including the Master-Detail wall and the without sharing elevation pattern. The piece closes with eight concrete risks (compile-time dependencies that block uninstall, upgrade coupling, silent cascade failures, access invisible to admins) and six actionable recommendations for keeping cross-project coupling manageable.
08 July 2026