public static IOException maybeExtractIOException(
      String path,
      Throwable thrown,
      String message) {

    if (thrown == null) {
      return null;
    }

    // walk down the chain of exceptions to find the innermost.
    Throwable cause = getInnermostThrowable(thrown.getCause(), thrown);

    // see if this is an http channel exception
    HttpChannelEOFException channelException =
        maybeExtractChannelException(path, message, cause);
    if (channelException != null) {
      return channelException;
    }

    // not a channel exception, not an IOE.
    if (!(cause instanceof IOException)) {
      return null;
    }

    // the cause can be extracted to an IOE.
    // rather than just return it, we try to preserve the stack trace
    // of the outer exception.
    // as a new instance is created through reflection, the
    // class of the returned instance will be that of the innermost,
    // unless no suitable constructor is available.
    final IOException ioe = (IOException) cause;

    return wrapWithInnerIOE(path, message, thrown, ioe);
  }
@Test
  public void testUncheckedIOExceptionExtraction() throws Throwable {
    intercept(SocketTimeoutException.class, "top",
        () -> {
          final SdkClientException thrown = sdkException("top",
              sdkException("middle",
                  new UncheckedIOException(
                      new SocketTimeoutException("bottom"))));
          throw maybeExtractIOException("p1",
              new NoAwsCredentialsException("IamProvider", thrown.toString(), thrown), null);
        });
  }