@Override
  public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
    try {
      if (request != null && request.isOpen() && cause instanceof Exception) {
        nettyMetrics.processorExceptionCaughtCount.inc();
        onRequestAborted((Exception) cause);
      } else if (isOpen()) {
        if (cause instanceof RestServiceException) {
          nettyMetrics.processorRestServiceExceptionCount.inc();
          RestServiceErrorCode errorCode = ((RestServiceException) cause).getErrorCode();
          if (ResponseStatus.getResponseStatus(errorCode) == ResponseStatus.BadRequest) {
            logger.debug("Swallowing error on channel {}", ctx.channel(), cause);
          } else {
            logger.error("Swallowing error on channel {}", ctx.channel(), cause);
          }
        } else if (cause instanceof IOException) {
          // for this case, it is certain that the server hasn't made any mistakes and the exception is probably
          // due to the client closing the connection. Therefore this is logged at the DEBUG level.
          nettyMetrics.processorIOExceptionCount.inc();
          logger.debug("Swallowing error on channel {}", ctx.channel(), cause);
        } else if (cause instanceof Exception) {
          nettyMetrics.processorUnknownExceptionCount.inc();
          logger.error("Swallowing error on channel {}", ctx.channel(), cause);
        } else {
          nettyMetrics.processorThrowableCount.inc();
          ctx.fireExceptionCaught(cause);
        }
        close();
      } else {
        nettyMetrics.processorErrorAfterCloseCount.inc();
        logger.debug("Caught error on channel {} after it was closed", ctx.channel(), cause);
      }
    } catch (Exception e) {
      String uri = (request != null) ? request.getUri() : null;
      nettyMetrics.exceptionCaughtTasksError.inc();
      logger.error("Swallowing exception during exceptionCaught tasks on channel {} for request {}", ctx.channel(), uri,
          e);
      close();
    }
  }
Netty calls this function when any exception is caught during the functioning of this handler.
<p/>
Centralized error handling based on the exception is performed here. Error responses are sent to the client via
the {@link RestResponseChannel} wherever possible.
<p/>
If this function throws an Exception, it is bubbled up to the handler before this one in the Netty pipeline.
@param ctx The {@link ChannelHandlerContext} that can be used to perform operations on the channel.
@param cause The cause of the error.
@throws Exception if there is an {@link Exception} while handling the {@code cause} caught.
ambry-rest/src/main/java/com/github/ambry/rest/NettyMessageProcessor.java