Http2 and HttpClientZioBackend

I am currently running an application using sttp and a HttpClientZioBackend, the server is behind a nginx that uses http2 and I noticed in the log that every hour, I get a stack trace with a

ent3.SttpClientException$ReadException: Exception when sending request: GET
        at sttp.client3.SttpClientExceptionExtensions.defaultExceptionToSttpClientException(SttpClientExceptionExtensions.scala:25)
        at sttp.client3.SttpClientExceptionExtensions.defaultExceptionToSttpClientException$(SttpClientExceptionExtensions.scala:9)
        at sttp.client3.SttpClientException$.defaultExceptionToSttpClientException(SttpClientException.scala:24)
        at sttp.client3.HttpClientAsyncBackend.adjustExceptions$$anonfun$1(HttpClientAsyncBackend.scala:147)
        at sttp.client3.SttpClientException$$anon$1.applyOrElse(SttpClientException.scala:35)
        at sttp.client3.SttpClientException$$anon$1.applyOrElse(SttpClientException.scala:34)
        at zio.ZIO.tryRescue$1$$anonfun$1(ZIO.scala:359)
        at scala.util.Either.fold(Either.scala:190)
        at zio.ZIO.tryRescue$1(ZIO.scala:359)
        at zio.ZIO.catchSome$$anonfun$1(ZIO.scala:361)
        Suppressed: /xxxxxxx:36150: GOAWAY received

It seems that this is related to the Module ngx_http_core_module (or keepalive_time) from nginx, which reset the connection every hour. This issue seems to be documented java - How to handle HTTP/2 GOAWAY with HttpClient? - Stack Overflow as well and I was wondering if there was a clean way to deal with that and maybe retry in case of GOAWAY using sttp ?

I could also provide a custom http client that explicitly disable HTTP2 to the HttpClientZioBackend, but that feels like a step backward.
Sorry if this is out of the scope of sttp

as of now, the only workaround that I can think of is doing that

      request = backend
                        .send(request.response(asBoth(request.response, asStringAlways)))
      result <- request.catchSome {
                  case exception: SttpClientException.ReadException if exception.getCause.toString.contains("GOAWAY") =>

which should work, another solution could be to switch to Armeria which seems to support http2 correctly (

Thanks for the report. I’m not sure if we can do something on sttp’s side - the linked SO post concludes that you can’t really do much, as the necessary details aren’t exposed by java’s HttpClient, unless I’m misunderstanding?

So you can only retry, or use Armeria ;). One possibility would be to include the retrying as part of sttp’s HttpClient integration, but that might be surprising to users. We’re then left with documenting the possible behavior?

I investigated a bit more yesterday, and using the workaround (dealing with the exception and using armeria) both worked. I’m really surprised that the native java client does not behave correctly when this is a documented situation well known for http2 but I think that indeed there is not much we should/could do as we don’t have the lastStreamId we can’t know if the client is supposed to retry or not.

Regarding the documentation, we could add that but I feel like this is pretty specific and would be quite odd in sttp’s documentation, maybe this post is enough ?
Thanks for the reply !

Ok. let’s keep this knowledge as part of this forum for now. We’ll see when we’ll get a similar report again :slight_smile:
Thanks for investigating!