IllegalReferenceCountException
Describe the bug When we upgraded from RC25 to RC27 our very simple server started throwing this exception
To Reproduce Sorry, not clear, it's a simple server, the request is a POST with json (circe) data, responding also with json data (though I don't think it gets that far)
Expected behaviour We shouldn't get an exception, and if we do, there should be clear logs.
Smartphone (please complete the following information):
- Device: reproduced locally on IOS or ubuntu cloud
Additional context Hey... after we upgraded from RC25 to RC27, we started getting the following error:
Uncaught failure: io.netty.util.IllegalReferenceCountException: refCnt: 0
<init>:30, IllegalReferenceCountException (io.netty.util)
ensureAccessible:1454, AbstractByteBuf (io.netty.buffer)
checkIndex:1383, AbstractByteBuf (io.netty.buffer)
checkDstIndex:1409, AbstractByteBuf (io.netty.buffer)
getBytes:1062, CompositeByteBuf (io.netty.buffer)
getBytes:2031, CompositeByteBuf (io.netty.buffer)
getBytes:49, CompositeByteBuf (io.netty.buffer)
getBytes:1336, ByteBufUtil (io.netty.buffer)
getBytes:1309, ByteBufUtil (io.netty.buffer)
getBytes:1301, ByteBufUtil (io.netty.buffer)
$anonfun$bodyAsByteArray$2:21, HttpDataExtension (zhttp.http)
apply:-1, HttpDataExtension$$Lambda$2824/0x000000080121c0c8 (zhttp.http)
evaluateNow:496, FiberContext (zio.internal)
$anonfun$fork$15:781, FiberContext (zio.internal)
run:-1, FiberContext$$Lambda$220/0x0000000800e0eba0 (zio.internal)
safeExecute$$$capture:164, AbstractEventExecutor (io.netty.util.concurrent)
safeExecute:-1, AbstractEventExecutor (io.netty.util.concurrent)
BTW.... I couldn't detect any logging on this issue coming out of zhttp or netty, so I had to go into the debugger, put a breakpoint in the exception's constructor and capture the stack trace from there.
Can you show use the code you are using to read the body? Also are you reading it more than once?
request <- req.bodyAsString.flatMap { str =>
implicit val decoder: Decoder[MyRequest] = myRequestDecoder(now)
(for {
json <- parse(str)
request <- json.as[MyRequest]
} yield request).fold(
e => ZIO.fail(BadRequestException(s"$str was not valid MyRequest: ${e.getMessage}")),
r => ZIO(r)
)
}
and yes, I think we're reading it more than once:
final protected def logJsonRequest(req: Request): ZIO[Logging, Nothing, Unit] = {
(for {
body <- req.bodyAsString
_ <- log.info(s"${req.method.toString()} request to ${req.url.encode}: " + parse(body).fold(_ => body, _.noSpaces))
} yield ()).ignore
}
I think we should throw a more appropriate error in case the content is read more than once. For performance reasons we don't allow reading data more than once right now.
We can even add a few operators to decode and cache data, thus giving user flexibility over ease-of-use vs performance.
This should be fixed in #1351.