Salesforce Developers Blog

Error Handling Best Practices for Lightning and Apex

Avatar for Philippe OzilPhilippe Ozil
This article deals with error handling for Aura components and will only be valuable for developers creating or maintaining custom UI using that framework. If you are looking for Lightning Web Components (LWC) error handling, please see our updated blog post from 2020.
Error Handling Best Practices for Lightning and Apex
September 28, 2017
Listen to this article
0:00 / 0:00

This article deals with error handling for Aura components and will only be valuable for developers creating or maintaining custom UI using that framework. If you are looking for Lightning Web Components (LWC) error handling, please see our updated blog post from 2020.

Sending a request from a Lightning component to an Apex Controller and getting back a response is a path that has several potential failure points. Developers sometimes assume for the sake of simplicity that “things will work” and don’t always perform all the proper error checks and handling. In this blog post we look at best practices for handling server-side and client-side errors.

Client-server communication overview

The Lightning Component framework is a client framework. It relies on Apex to perform backend operations such as accessing data.

Exchanges between the two sides follow a common request-response pattern.

  1. A Lightning component sends a request to its Apex controller using a server-side action.
  2. The controller processes the request. This can trigger a server-side error (permission issue, invalid query).
  3. The controller sends a response to the Lightning component.
  4. The Lightning component processes the response in a callback function. This can trigger a client-side error (unexpected response).

Generic client-server roundtrip

If we omit the network-related errors, this pattern can trigger two types of errors that developers must handle: server-side and client-side errors.

Server-side errors

Quick refresher on Apex server-side controller

The Lightning Component framework communicates with Apex via server-side actions. These actions are declared as static methods annotated with @AuraEnabled (documentation).

1public with sharing class SimpleServerSideController {
2
3    // Exposing a server-side action to Lightning
4    @AuraEnabled
5    public static String serverEcho(String firstName) {
6        return ('Hello from the server, ' + firstName);
7    }
8}

What to avoid

Processing a server request can trigger errors due to a variety of causes such as permission issues, invalid queries, or Apex limits being reached. These errors take the form of an Exception being thrown in the Apex code.

If you process a failing server request as is (see code below), a system exception is returned to the Lightning component.

1// Bad practice: error message is not user-friendly or informative
2@AuraEnabled
3public static void triggerInternalError() {
4    integer a = 1 / 0; // Division by zero causes exception
5}

Doing so is bad practice as this results in a generic error message: “An internal server error has occurred” or “Sorry to interrupt”. This is not user-friendly and provides no information about the error. We all hate that. 🙁

System error

Basic error handling

Thankfully, the solution to this problem is quite simple.

  1. Wrap the code that can trigger exceptions in a try-catch block.
  2. Throw an AuraHandledException in the catch block. This allows you to provide a custom user-friendly error message.

Here is the code of the previous example updated with this best practice.

1// Best practice: user-friendly error message provided by an AuraHandledException
2@AuraEnabled
3public static void triggerBasicAuraHandledError() {
4    try {
5        integer a = 1 / 0; // Division by zero causes exception
6    }
7    catch (Exception e) {
8        // "Convert" the exception into an AuraHandledException
9        throw new AuraHandledException('Darn it! Something went wrong: '
10            + e.getMessage());    
11    }
12    finally {
13        // Something executed whether there was an error or not
14    }
15}

The AuraHandledException is sent back to the client with your custom message, and you’re free to display it in the way you want using the Lightning Component framework.

Custom error handling

The previous solution is good enough for basic error handling, but what if you have a complex processing logic and require more information about the error on the client-side? How about adding an exception name and an error code?

Unfortunately, you cannot extend AuraHandledException to create a custom exception because it is not an extensible Apex class. However, there is a trick that can help you bypass this limitation.

You can add custom data to your AuraHandledException by following these steps.

  1. Create a simple wrapper class that can hold the data.
1// Wrapper class for my custom exception data
2public class CustomExceptionData {
3    public String name;
4    public String message;
5    public Integer code;
6
7    public CustomExceptionData(String name, String message, Integer code) {
8        this.name = name;
9        this.message = message;
10        this.code = code;
11    }
12}
  1. Instantiate your custom class, serialize it as JSON, then pass it to the AuraHandledException.
1// Throw an AuraHandledException with custom data
2CustomExceptionData data = new CustomExceptionData('MyCustomServerError', 'Some message about the error', 123);
3throw new AuraHandledException(JSON.serialize(data));
  1. Finally, on the client-side (Lightning controller or helper), parse the error message string as JSON, and access your custom error data.
1// Parse custom error data & report it
2let errorData = JSON.parse(error.message);
3console.error(errorData.name +" (code "+ errorData.code +"): "+ errorData.message);

Client-side errors

Processing a response on the client-side can trigger several types of errors as well. These typically occur when the client receives an answer from the server that does not meet its expectations. This can be caused by a remote technical error such as an AuraHandledException or a value that does not meet certain business rules.

Quick refresher on Lightning Server-Side Actions

The Lightning Component framework uses Server-Side Actions to perform requests on Apex controllers. This is done in five steps.

1// Calling a server-side action
2({
3    callServerSideAction : function(cmp) {
4        // 1. Retrieve an action object by specifying the
5        //    Apex method that will be called
6        let action = cmp.get("c.myApexEndpoint");
7
8        // 2. Optionally set some action parameters
9        action.setParams({ firstName : cmp.get("v.firstName") });
10
11        // 3. Configure a callback function that will be
12        //    executed to handle the server response
13        action.setCallback(this, function(response) {
14            // Some response processing code
15        });
16
17        // 4. Optionally set some action configuration flags
18
19        // 5. Enqueue the action so that the framework processes it
20        $A.enqueueAction(action);
21    }
22})

For the sake of brevity, we only focus on the callback function in this article. It exposes one argument that is an object holding the response sent by the server.

The first thing to do upon entering the callback function is to check the response state with response.getState(). This function can return different state values, but you should at least check for SUCCESS and ERROR states.

1// Server-side action callback
2function(response) {
3    // Checking the server response state
4    let state = response.getState();
5    if (state === "SUCCESS") {
6        // Process server success response
7        let returnValue = response.getReturnValue();
8    }
9    else if (state === "ERROR") {
10        // Process error returned by server
11    }
12    else {
13        // Handle other reponse states
14    }
15}

Handling a server error

If the state of the response is ERROR, you need to handle a server error. You can access the errors details with the response.getError() function, but there’s a catch: Despite its name, this function returns an array of errors, not just a single one.

In most of the cases, you want to check the first error of this array, but keep in mind that there can be more than one. Here’s the minimal code that covers that.

1let errors = response.getError();
2let message = 'Unknown error'; // Default error message
3// Retrieve the error message sent by the server
4if (errors && Array.isArray(errors) && errors.length > 0) {
5    message = errors[0].message;
6}
7// Display the message
8console.error(message);

Note that you should avoid using console.log() to report errors. Use console.error() instead. This ensures that your errors are properly reported in your browser’s developer tools. It’s easy to miss an error in a stack full of info or debug messages.

Reporting the error in the console is a start, but the end goal is to display it to the user. The easiest way to do this if you’re working on a page that’s rendered in Lightning Experience is to display a Lightning Toast notification. You can do so by calling the following helper function while passing it the return value of response .getError().

1handleErrors : function(errors) {
2    // Configure error toast
3    let toastParams = {
4        title: "Error",
5        message: "Unknown error", // Default error message
6        type: "error"
7    };
8    // Pass the error message if any
9    if (errors && Array.isArray(errors) && errors.length > 0) {
10        toastParams.message = errors[0].message;
11    }
12    // Fire error toast
13    let toastEvent = $A.get("e.force:showToast");
14    toastEvent.setParams(toastParams);
15    toastEvent.fire();
16}

Throwing and catching client-side errors

Client-side errors take the form of a JavaScript Error being thrown. An Error is very similar to Apex Exception: It’s a type built with a constructor, and it supports the same throw-catch syntax.

1try {
2    // Something that could throw an error
3    throw new Error('Error message goes here');
4} catch (e) {
5    // Error handling
6    console.error(e);
7} finally {
8    // Something executed whether there was an error or not
9}

Just like Apex Exceptions, JavaScript Errors enable you to separate result values from errors when you call a function. For instance, if you follow best practices and let your helper do the heavy-lifting, you can write code like this in your controller:

1try {
2    // Call a function that may throws an Error
3    let value = helper.doSomethingThatMightFails();
4    // Process value if function succeeded
5} catch (e) {
6    // Handle error
7    console.error(e);
8}

Custom client-side errors

If a text message is not enough data to describe your error, you can extend the JavaScript standard Error type and create errors with custom attributes.

1// Declaring a custom error type
2function MyCustomError(name, message, code) {
3    this.name = name;
4    this.message = message;
5    this.code = code;
6    this.stack = (new Error()).stack;
7}
8MyCustomError.prototype = Object.create(Error.prototype);
9MyCustomError.prototype.constructor = MyCustomError;

You can then throw it and catch it with this code.

1// Throwing and catching a custom error
2try {
3    throw new MyCustomError('MyCustomError', 'Custom error message', 456);
4} catch (e) {
5    if (e instanceof MyCustomError) {
6        // Specific message for MyCustomError
7        console.error(e.name +' (code '+ e.code +'): '+ e.message);
8    }
9    else {
10        // Generic message for other types of error
11        // (unreachable code in this sample)
12        console.error(e.message);
13    }
14}

Closing words

We’ve covered the different types of errors that can occur when processing client-server communications. You now know how to handle those different errors and how to extend them to fit your needs.

Client-server roundtrip tips

How about trying those different options in an interactive playground and studying some sample code?

Error playground animation

Resources

More Blog Posts

The Salesforce Developer’s Guide to the Winter ’25 Release

The Salesforce Developer’s Guide to the Winter ’25 Release

The Winter '25 release is here! In this post, we highlight what’s new for developers across the Salesforce ecosystem.September 03, 2024

The Developer’s Guide to Dreamforce 2025

The Developer’s Guide to Dreamforce 2025

Get ready for Dreamforce 2025, whether you’re joining in San Francisco or on Salesforce+.September 17, 2025

The Salesforce Developer’s Guide to the Winter ’26 Release

The Salesforce Developer’s Guide to the Winter ’26 Release

Learn about highlights for developers in the Winter '26 release across Lightning Web Components, Apex, Salesforce Platform developer tools, APIs, and more.September 08, 2025