Skip to content

Lack of Exception Handling in onResponse Causes Thread Hang #1614

@jonasasx

Description

@jonasasx

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 onFailure is invoked nor is there any fallback logic to recover or terminate the execution.

Steps to Reproduce

  1. Use MinIO Java SDK io.minio:minio:8.5.15.

  2. Perform an operation (e.g., statObject) that invokes executeAsync() 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 NullPointerException or simulate a JSON parsing failure.
  3. Observe:

    • OkHttp logs the message "Callback failure for...".
    • The thread handling the callback hangs indefinitely, leaving the application in an inconsistent state.

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:

  1. Prevent unhandled exceptions from propagating to OkHttp and leaving threads in a hung state.
  2. Allow the application to safely recover from the failure via onFailure or 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 onResponse makes 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.

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions