AWS Developer Tools Blog

Error Handling in Modular AWS SDK for JavaScript (v3)

In the version 3.53.0 of the modular AWS SDK for JavaScript (v3), we introduced concrete classes for AWS service exceptions which support asserting service exceptions with instanceof operator. In this post, we cover how to use it and how it improves the error handling experience.

Why did we do it?

Previously, the AWS SDK for JavaScript (v3) users could not assert the service exceptions’ types as the SDK threw service exceptions as plain JavaScript objects. The application code could handle exceptions only by comparing value for the object key name to the expected error code string as shown in the code below:

try {
  await client.send(someCommand);
} catch (e) {
  if (e.name === "InvalidSignatureException") {
    // Handle InvalidSignatureException
  } else if (e.name === "ResourceNotFoundException") {
    // Handle ResourceNotFoundException
  } else if (e.name === "FooServiceException") {
    // Handle all other server-side exceptions from Foo service
  } else {
    // Handle errors from SDK
  }
}

As a result, you had to know the error codes of all the errors to handle and hard-code the expected error codes in your application. Moreover, only TypeScript code could cast the caught exceptions to the provided service exception interfaces. The JavaScript code could not use IntelliSense code-completion aid to access any traits from the service exceptions.

We had received multiple requests for improving this feature. For example, AWS SDE Daniel Lees had asked this question on internal slack channel:

Hello, does anyone know why js aws sdk v3 doesn’t throw Errors or sub-classes of errors? Or at least objects in the shape of an Error? Technically it is not a javascript requirement to throw Errors or Error sub-classes, but it is generally considered good practice eslint, typescript-eslint,

The GitHub user Lambros Petrou said in aws/aws-sdk-js-v3/#2007

It would be great to have concrete type definitions for TypeScript that is easy to use the error responses, similar to the happy case with XxxCommandInput/Output types.

How to handle Service Exceptions using classes?

As the result of this change, the SDK now constructs all the exceptions from the server side in specific classes. You can use instanceof to assert if a caught exception is expected as follows:

import {
  InvalidSignatureException,
  ResourceNotFoundException,
  FooServiceException,
} from "@aws-sdk/client-foo";

try {
  await client.send(someCommand);
} catch (e) {
  if (e instanceof InvalidSignatureException) {
    // Handle InvalidSignatureException
  } else if (e instanceof ResourceNotFoundException) {
    // Handle ResourceNotFoundException
  } else if (e instanceof FooServiceException) {
    // Handle all other server-side exceptions from Foo service
  } else {
    // Other errors
  }
}

In the example above, InvalidSignatureException and ResourceNotFoundException are two exceptions thrown by the someCommand that needs special handling. You can use e instanceof InvalidSignatureException statement to assert whether the exception is an instance of a given class.

Once the error is asserted, the e is casted to the given exception type automatically. As a result, you can get code highlights and autocomplete from the IDE you are using as shown below:

It is a common use case to handle any server-side exceptions for a given service as the default case in error handling code block. As shown in the code snippet above, the FooServiceException serves exactly this case. For each service client, the base class for all server-side exceptions is named as [ServiceId]ServiceException. For example, the base class name for S3 service is called S3ServiceException.

This change is backward compatible—all the existing error handling code will still work. You can still assert the error by the name value.

What to expect in service exception classes?

In each server-side exception instance, we provide a handful of useful shared traits that can assist your error handling logic.

The graph below provides an overview:

Here’s a break-down of available error traits:

  • name: The error code of the given exception. It’s usually the same as the class name.
  • message: The error message indicating the cause of the error.
  • $response: Optional nonenumerable reference to the raw response object (e.g. HTTP Incoming Message).
  • $retryable: Optional hash indicating an error may be retried by the client.
  • $fault: The string mentioning if ‘client’ or ‘server’ is at fault for the given exception.
  • stack: The stack trace of the given error.

How can you contribute?

We value your feedback, so please tell us what you like and don’t like by opening an issue on GitHub.

Allan Zheng

Allan Zheng

Allan is maintainer of AWS SDK for JavaScript in Node.js and browser. He builds tools helping users navigating the AWS. Find him on GitHub @AllanZhengYP.