@Test
  void throwsRetryableExceptionIfNoUnderlyingCause() throws Throwable {
    server.enqueue(new MockResponse().setResponseCode(503).setBody("foo 1"));
    server.enqueue(new MockResponse().setResponseCode(503).setBody("foo 2"));

    String message = "play it again sam!";

    TestInterfaceAsync api =
        AsyncFeign.builder()
            .exceptionPropagationPolicy(UNWRAP)
            .retryer(new Retryer.Default(1, 1, 2))
            .errorDecoder(
                (methodKey, response) ->
                    new RetryableException(
                        response.status(),
                        message,
                        HttpMethod.POST,
                        NON_RETRYABLE,
                        response.request()))
            .target(TestInterfaceAsync.class, "http://localhost:" + server.getPort());

    Throwable exception = assertThrows(RetryableException.class, () -> unwrap(api.post()));
    assertThat(exception.getMessage()).contains(message);
  }
when you must parse a 2xx status to determine if the operation succeeded or not.
core/src/test/java/feign/AsyncFeignTest.java