Handling Errors

Learn how to handle errors and exceptions.

Java errors are thrown as exceptions when you build or run your application. The NoSQLException class is the base for most exceptions thrown by the driver. However, the driver throws exceptions directly for some classes, such as IllegalArgumentException and NullPointerException.

In general, NoSQL exception instances are split into two broad categories:

  • Exceptions that may be retried with the expectation that they may succeed on retry.

    These exceptions are instances of the RetryableException class. These exceptions usually indicate resource consumption violations.

  • Exceptions that will fail even after retry.

    Examples of exceptions that should not be retried are IllegalArgumentException, TableNotFoundException, and any other exception indicating a syntactic or semantic error.

Python errors are raised as exceptions defined as part of the API. They are all instances of Python’s RuntimeError. Most exceptions are instances of borneo.NoSQLException which is a base class for exceptions raised by the Python driver.

Exceptions are split into 2 broad categories: Exceptions that may be retried with the expectation that they may succeed on retry. These are all instances of borneo.RetryableException. Examples of these are the instances of borneo.ThrottlingException which is raised when resource consumption limits are exceeded. Exceptions that should not be retried, as they will fail again. Examples of these include borneo.IllegalArgumentException , borneo.TableNotFoundException, etc.

borneo.ThrottlingException instances will never be thrown in an on-premise configuration as there are no relevant limits.

Go SDK errors are reported as nosqlerr.Error values defined as part of the API. Errors are split into 2 broad categories:
  • Errors that may be retried with the expectation that they may succeed on retry. These are retryable errors on which the Error.Retryable() method call returns true. Examples of these include nosqlerr.OperationLimitExceeded, nosqlerr.ReadLimitExceeded, nosqlerr.WriteLimitExceeded, which are raised when resource consumption limits are exceeded.
  • Errors that should not be retried, as they will fail again. Examples of these include nosqlerr.IllegalArgumentError, nosqlerr.TableNotFoundError, etc.

Asynchronous methods of NoSQLClient return Promise as a result and if an error occurs it results in the Promise rejection with that error. For synchronous methods such as NoSQLClient constructor errors are thrown as exceptions. All errors used by the SDK are instances of NoSQLError or one of its subclasses. In addition to the error message, each error has errorCode property set to one of standard error codes defined by the ErrorCode enumeration. errorCode may be useful to execute conditional logic depending on the nature of the error.

For some error codes, specific subclasses of NoSQLError are defined, such as NoSQLArgumentError, NoSQLProtocolError, NoSQLTimeoutError, etc. NoSQLAuthorizationError may have one of several error codes depending on the cause of authorization failure. In addition, errors may have cause property set to the underlying error that caused the current error. Note that the cause is optional and may be an instance of an error that is not part of the SDK.

In addition, error codes are split into 2 broad categories:
  • Errors that may be retried with the expectation that the operation may succeed on retry. Examples of these are ErrorCode.READ_LIMIT_EXCEEDED and ErrorCode.WRITE_LIMIT_EXCEEDED which are throttling errors (relevant for the Cloud environment), and also ErrorCode.NETWORK_ERROR since most network conditions are temporary.
  • Errors that should not be retried, as the operation will most likely fail again. Examples of these include ErrorCode.ILLEGAL_ARGUMENT (represented by NoSQLArgumentError), ErrorCode.TABLE_NOT_FOUND, etc.
You can determine if the NoSQLError is retryable by checking retryable property. Its value is set to true for retryable errors and is false or undefined for non-retryable errors.

Retry Handler

The driver will automatically retry operations on a retryable error. Retry handler determines:
  • Whether and how many times the operation will be retried.
  • How long to wait before each retry.
RetryHandler is an interface with with 2 properties:
  • RetryHandler#doRetry that determines whether the operation should be retried based on the operation, number of retries happened so far and the error occurred. This property is usually a function, but may be also be set to boolean false to disable automatic retries.
  • RetryHandler#delay that determines how long to wait before each successive retry based on the same information as provided to RetryHandler#doRetry. This property is usually a function, but may also be set to number of milliseconds for constant delay.
NoSQLException serves as a base class for many exceptions thrown by the driver. However, in certain cases the driver uses standard exception types such as:
  • ArgumentException and its subclasses such as ArgumentNullException. They are thrown when an invalid argument is passed to a method or when an invalid configuration (in code or in JSON) is passed to create NoSQLClient instance.
  • TimeoutException is thrown when an operation issued by NoSQLClient has timed out. If you are getting many timeout exceptions, you may try to increase the timeout values in NoSQLConfig or in options argument passed to the NoSQLClient method.
  • InvalidOperationException is thrown when the service is an invalid state to perform an operation. It may also be thrown if the query has failed be cause its processing exceeded the memory limit specifed in QueryOptions.MaxMemoryMB or NoSQLConfig.MaxMemoryMB. In this case, you may increase the corresponding memory limit. Otherwise, you may retry the operation.
  • InvalidCastException and OverflowException may occur when working with sublcasses of FieldValue and trying to cast a value to a type it doesn't support or cast a numeric value to a smaller type causing arithmetic overflow.
  • OperationCanceledException and TaskCanceledException if you issued a cancellation of the operation started by a method of NoSQLClient using the provided CancellationToken.
In addition, exceptions may be split into two broad categories:
  • Exceptions that may be retried with the expectation that the operation may succeed on retry. In general these are subclasses of RetryableException. These include throttling exceptions as well as other exceptions where a resource is temporarily unavailable. Some other subclasses of NoSQLException may also be retryable depending on the conditions under which the exception occurred. In addition, network-related errors are retryable because most network conditions are temporary.
  • Exceptions that should not be retried because they will still fail after retry. They include exceptions such as TableNotFoundException, TableExistsException and others as well as standard exceptions such as ArgumentException.
You can determine if a given instance of NoSQLException is retryable by checking its IsRetryable property.

Retry Handler

By default, the driver will automatically retry operations that threw a retryable exception (see above). The driver uses retry handler to control operation retries. The retry handler determines:
  • Whether and how many times the operation will be retried.
  • How long to wait before each retry.
All retry handlers implement IRetryHandler interface. This interface provides two methods, one to determine if the operation in its current state should be retried and another to determine a retry delay before the next retry. You have a choice to use default retry handler or set your own retry handler as RetryHandler property of NoSQLConfig when creating NoSQLClient instance.

Note:

Retries are only performed within the timeout period alloted to the operation and configured as one of timeout properties in NoSQLConfig or in options passed to the NoSQLClient method. If the operation or its retries have not succeded before the timeout is reached, TimeoutException is thrown.
By default, the driver uses NoSQLRetryHandler class which controls retires based on operation type, exception type and whether the number of retries performed has reached a preconfigured maximum. It also uses exponential backoff delay to wait between retries starting with a pre configured base delay. You may customize the properties such as maximum number of retries, base delay and others by creating your own instance of NoSQLRetryHandler and setting it as a RetryHandler property in NoSQLConfig. For example:
var client = new NoSQLClient(
    new NoSQLConfig
    {
        Region = .....,
        ...............
        RetryHandler = new NoSQLRetryHandler
        {
            MaxRetryAttempts = 20,
            BaseDelay = TimeSpan.FromSeconds(2)
        }
    });
If you don't specify the retry handler, the driver will use an instance of NoSQLRetryHandler with default values for all parameters. Alternatively, you may choose to create your own retry handler class by implementing IRetryHandler interface. The last option is to disable retries all together. You may do this if you plan to retry the operations within your application instead. To disable retries, set RetryHandler property of NoSQLConfig to NoRetries:
var client = new NoSQLClient(
    new NoSQLConfig
    {
        Region = .....,
        ...............
        RetryHandler = NoSQLConfig.NoRetries
    });

Handle Resource Limits: Programming in a resource-limited environment can be challenging. Tables have user-specified throughput limits and if an application exceeds those limits it may be throttled, which means an operation may fail with one of the throttling exceptions such as ReadThrottlingException or WriteThrottlingException. This is most common when using queries, which can read a lot of data, using up capacity very quickly. It can also happen for get and put operations that run in a tight loop.

Even though throttling errors will be retried and using custom RetryHandler may allow more direct control over retries, an application should not rely on retries to handle throttling as this will result in poor performance and inability to use all of the throughput available for the table. The better approach would be to avoid throttling entirely by rate-limiting your application. In this context rate-limiting means keeping operation rates under the limits for the table.

The Spring Data errors are thrown as exceptions when you build or run your application.

The Spring Data SDK uses IllegalArgumentException for invalid parameters and passes through Java SDK and Spring Framework exceptions. The Spring framework throws exceptions directly for some classes, such as BeansException.

You can add an exception code block to catch any error that might be thrown such as authentication failure during connection setup. Additionally, you can enable logging in Oracle NoSQL Database SDK for Spring Data at ERROR and DEBUG levels. For more details, see Activating Logging in the Spring Data SDK Developers Guide.