Handling Exceptions and Other Errors with the .NET SDK in Couchbase

This section gives an overview of the kind of error handling a .NET program will want to consider, properties of results, and the kinds of exceptions you should plan to handle.

How the SDK Handles Errors

The .NET SDK generally handles errors in two ways: either by catching an internally thrown exception and returning it back the application tier as a property of the IDocumentResult or by throwing the exception with the expectation that the application will handle it. The general rule is if the error is scoped to an operation or query, then it’s handled gracefully and returned as part of the response. If the error is scoped to the client internals and non-recoverable, then the exception is thrown to the application. An example of an error that is caught and returned as a property of the response would be an OperationTimeoutException. A non-recoverable error such as a BootstrapException would be thrown since the client cannot function without successfully bootstrapping to the server.

Useful Properties of IResult and its Derivatives

The Document, Query (N1QL) and View API methods all return results that inherit from a common interface: IResult. The IResult interface contains signatures for the following properties:

  • Success: returns a boolean value indicating whether the overall operation or request was successful or not.

  • Message: returns an optional message if Success was false - this may indicate the reason for the failure.

  • Exception: if Success was false an optional exception if one was generated.

The purpose of these properties is to provide information regarding the operation and if it was a failure, enough information to diagnose or handle the error within the application. For example, in the event of a failure, the application may decide to rethrow the exception up the stack or perhaps log the error and keep on going.

var result = bucket.GetDocument("thekey");
if(!result.Success && result.Exception != null){
  throw result.Exception;
}

There is also an interface that inherits IResult called IResult<T> which has a Value property of Type "T"; its purpose is for operations that retrieve a document from Couchbase. A good example would be IBucket.GetDocument<T>(string id) which retrieves a document from Couchbase and casts it to whatever you specify as T (assuming the document is compatible with whatever T is).

As mentioned previously, each SDK has its own IResult specification which extends the definition for its own domain-specific purpose. Query has an IQueryResult<T> and Views has an IViewResult. Since both of have IResult in the inheritance chain, they share implementations of the common properties above, plus much more.

iresult interface inheritence

For more detail on each specific implementation, look within the section for each of the respective APIs: Document, Query, Full Text Search and Views.

The Exception Types and Their Meanings

As mentioned previously, the .NET SDK differentiates between throwing non-recoverable exceptions and returning recoverable exceptions as part of the IResult.Exception property. The following table defines each exception type in the SDK and the behavior of the client when it is encountered.

Table 1. Overview of .NET SDK Exceptions
Name Description

BootstrapException

The client failed to bootstrap for one more reasons. See Note below.

AuthenticationException

The client failed to authenticate - thrown along with BootstrapException. See Note below.

ConfigException

The client could not bootstrap for a given provider type. Client will generally recover if a Memcached bucket.

CouchbaseBootstrapException and BootstrapException

An error occurred while bootstrapping the client on a Couchbase bucket.

BucketAlreadyOpenException

An attempt to open a bucket that has already been opened.

BucketNotFoundException

A bucket was referenced that does not exist.

DocumentMutationLostException

If enhanced durability is enabled, indicates a non-recoverable state when using an overload.

InitializationException

A failure occurred during initialization.

NodeUnavailableException

Thrown if a node in the cluster is not online to service a pending request.

ReplicaNotConfiguredException

Thrown if requested ReplicateTo value exceeds the number of configured replicas on the Server.

ServiceNotSupportedException

Thrown if a service (Data, Query, etc) is requested that is not supported or configured on the cluster.

BufferUnavailableException

Thrown when an available buffer cannot be obtained from the BufferAllocator.

ConnectionUnavailableException

Thrown when an available IConnection cannot be obtained from the IConnectionPool after a number of tries.

RemoteHostClosedException

Thrown when the remote host closes a connection.

RemoteHostTimeoutException

Thrown when an in-process operation times out.

IndexAlreadyExistsException

Thrown when attempting to create an index that already exists.

IndexDoesNotExistException

Thrown when an attempt is made to use an index that does not exist.

PrepareStatementException

Thrown when the IQueryClient cannot prepare a non-adhoc statement on the server.

NullConfigException

Thrown when a node locator can not be found. This generally indicates a problem in the client internals.

ServerUnavailableException

Thrown when the client representation of a remote host cannot be located to fulfill a request.

UnsupportedAddressFamilyException

Thrown if an IP cannot be resolved from a domain name.

System.TimeoutException

Thrown if a request cannot be fulfilled by the configured timeout.

both BootstrapException and AuthenticationException will nearly always be wrapped in a System.AggregateException.
not all exceptions are returned back to application or thrown - in many appropriate cases they are handled internally and logged. This should be considered when using a debugger to break on exceptions.