class DeFramer extends ByteToMessageDecoder {

  @Override
  public void exceptionCaught(final ChannelHandlerContext ctx, final Throwable throwable)
      throws Exception {
    final Throwable cause =
        throwable instanceof DecoderException && throwable.getCause() != null
            ? throwable.getCause()
            : throwable;
    if (cause instanceof FramingException
        || cause instanceof RLPException
        || cause instanceof IllegalArgumentException) {
      LOG.debug("Invalid incoming message", throwable);
      if (connectFuture.isDone() && !connectFuture.isCompletedExceptionally()) {
        connectFuture.get().disconnect(DisconnectMessage.DisconnectReason.BREACH_OF_PROTOCOL);
        return;
      }
    } else if (cause instanceof IOException) {
      // IO failures are routine when communicating with random peers across the network.
      LOG.debug("IO error while processing incoming message", throwable);
    } else {
      LOG.error("Exception while processing incoming message", throwable);
    }
    if (connectFuture.isDone() && !connectFuture.isCompletedExceptionally()) {
      connectFuture
          .get()
          .terminateConnection(DisconnectMessage.DisconnectReason.TCP_SUBSYSTEM_ERROR, true);
    } else {
      connectFuture.completeExceptionally(throwable);
      ctx.close();
    }
  }

    DeFramer(
      final Framer framer,
      final List<SubProtocol> subProtocols,
      final LocalNode localNode,
      final Optional<Peer> expectedPeer,
      final PeerConnectionEventDispatcher connectionEventDispatcher,
      final CompletableFuture<PeerConnection> connectFuture,
      final MetricsSystem metricsSystem);

}