-
Notifications
You must be signed in to change notification settings - Fork 516
Description
In the library io.minio:minio:8.5.15 with com.squareup.okhttp3:okhttp:4.12.0, the onResponse implementation in OkHttp's Callback does not handle exceptions. Specifically, in the callback initialized within the method:
io.minio.S3Base.executeAsync(io.minio.http.Method, java.lang.String, java.lang.String, java.lang.String, okhttp3.Headers, com.google.common.collect.Multimap<java.lang.String,java.lang.String>, java.lang.Object, int)when httpClient.newCall(request).enqueue() is called, if an exception is thrown from onResponse, it leads to unhandled errors that result in thread hanging. The failure is silently logged by OkHttp, and no further handling or fallback logic is enforced.
This issue greatly impacts the reliability of asynchronous calls because an exception during response handling leads to an incomplete callback execution without notifying the user or safely terminating the request.
Exception example:
j.n.ProtocolException: unexpected end of stream
at o.i.h.Http1ExchangeCodec$FixedLengthSource.read(Http1ExchangeCodec.kt:400)
at o.i.c.Exchange$ResponseBodySource.read(Exchange.kt:291)
at o.RealBufferedSource.select(RealBufferedSource.kt:233)
at o.internal._UtilJvmKt.readBomAsCharset(-UtilJvm.kt:99)
at okhttp3.ResponseBody.string(ResponseBody.kt:176)
at io.minio.S3Base$1.onResponse(S3Base.java:650)
at o.i.c.RealCall$AsyncCall.run(RealCall.kt:529)
at j.u.c.ThreadPoolExecutor.runWorker(Unknown Source)
at j.u.c.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
Expected Behavior
Exceptions inside the onResponse method:
- Should be caught by the library and properly logged or handled.
- Should either notify the user via
onFailure(if applicable) or gracefully terminate the thread without hanging.
Observed Behavior
When an exception is thrown inside the onResponse implementation during the processing phase:
- The exception propagates up to OkHttp.
- OkHttp logs the failure as:
Callback failure for <call details>: <exception>
- The thread handling the callback hangs indefinitely, as neither
onFailureis invoked nor is there any fallback logic to recover or terminate the execution.
Steps to Reproduce
-
Use MinIO Java SDK
io.minio:minio:8.5.15. -
Perform an operation (e.g.,
statObject) that invokesexecuteAsync()for an asynchronous HTTP call:- Inside the callback's
onResponse, add a line of code that forces a runtime exception. - For example, forcefully throw a
NullPointerExceptionor simulate a JSON parsing failure.
- Inside the callback's
-
Observe:
- OkHttp logs the message
"Callback failure for...". - The thread handling the callback hangs indefinitely, leaving the application in an inconsistent state.
- OkHttp logs the message
Affected Code
The issue stems from the MinIO SDK's delegated callback created in:
httpClient
.newCall(request)
.enqueue(callback)The Callback initialized within executeAsync() does not have proper exception handling around the onResponse implementation, which allows exceptions to propagate to OkHttp without being intercepted.
Suggested Solution
To fix this issue, ensure that exceptions within the callback are safely caught and handled. Specifically, wrap the body of onResponse in a try-catch block. For example:
@Override
public void onResponse(Call call, Response response) {
try {
// Current logic of handling response
} catch (Exception e) {
// Handle the exception gracefully
log.error("Exception in onResponse: ", e);
onFailure(call, e); // Gracefully notify the application of the failure
}
}This will:
- Prevent unhandled exceptions from propagating to OkHttp and leaving threads in a hung state.
- Allow the application to safely recover from the failure via
onFailureor another fallback mechanism.
Environment Information
- MinIO Java SDK Version:
8.5.15 - Java Version:
17 - OkHttp Version:
4.12.0 - Operating System:
Windows 11
Additional Context
- The absence of proper exception handling in
onResponsemakes it extremely difficult to debug asynchronous issues. Uncaught exceptions result in incomplete execution paths, leaving threads stuck in a semi-active state. - This not only affects app stability but also violates expectations for how MinIO's SDK should handle real-world failures gracefully.