{"record":{"id":"1a47584717b1ac29","repo":"apache/druid","slug":"interrupted-1a4758","errorCode":null,"errorMessage":"Interrupted!","messagePattern":"Interrupted!","errorType":"error_code","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"processing/src/main/java/org/apache/druid/java/util/http/client/io/AppendableByteArrayInputStream.java","lineNumber":146,"sourceCode":"  {\n    long numScanned = 0;\n    long numPulled = 0;\n\n    while (numToScan > numScanned) {\n      if (currIndex >= curr.length) {\n        synchronized (singleByteReaderDoer) {\n          if (bytes.isEmpty()) {\n            if (done) {\n              break;\n            }\n            try {\n              available -= numPulled;\n              numPulled = 0;\n              singleByteReaderDoer.wait();\n            }\n            catch (InterruptedException e) {\n              Thread.currentThread().interrupt();\n              throw new IOException(\"Interrupted!\");\n            }\n          }\n\n          if (throwable != null) {\n            throw new IOException(throwable);\n          }\n\n          if (bytes.isEmpty()) {\n            if (done) {\n              break;\n            } else {\n              log.debug(\"bytes was empty, but read thread was awakened without being done.  This shouldn't happen.\");\n              continue;\n            }\n          }\n\n          curr = bytes.removeFirst();\n          currIndex = 0;","sourceCodeStart":128,"sourceCodeEnd":164,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/processing/src/main/java/org/apache/druid/java/util/http/client/io/AppendableByteArrayInputStream.java#L128-L164","documentation":"AppendableByteArrayInputStream.scanThroughBytesAndDoSomething waits on a monitor for more bytes to arrive from the async HTTP response. If the waiting thread is interrupted, it restores the interrupt flag and throws IOException(\"Interrupted!\") to abort the read. The underlying cause (e.g. connection closed or stream aborted) is also surfaced as an IOException when the producer recorded a throwable.","triggerScenarios":"A thread blocked in read()/skip() waiting for more bytes when another thread interrupts it — typically caller cancellation, executor shutdown, or a request timeout canceling the future and interrupting the reading thread.","commonSituations":"Druid query cancellation interrupting the thread pulling an HTTP response body; segment loading or task threads being interrupted on shutdown; timeouts that interrupt in-flight response consumption.","solutions":["Treat it as cancellation: check Thread.currentThread().isInterrupted() and unwind gracefully; do not swallow the flag (the code already re-interrupts).","If interruption is unexpected, find who interrupts the thread (query cancellation, timeout, shutdown hook) and fix the lifecycle.","Retry the HTTP fetch if the operation is idempotent and the interruption was spurious.","Ensure the http client future/response is fully consumed or properly canceled to avoid blocked waits."],"exampleFix":"// before\ntry (InputStream in = responseHandler.getStream()) {\n  in.readAllBytes(); // IOException(\"Interrupted!\") propagates raw\n} catch (IOException e) {\n  throw new RuntimeException(e); // loses interrupt semantics\n}\n// after\ntry (InputStream in = responseHandler.getStream()) {\n  in.readAllBytes();\n} catch (InterruptedIOException e) {\n  Thread.currentThread().interrupt();\n  throw new QueryInterruptedException(\"Query cancelled\");\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  stream.read(...);\n} catch (IOException e) {\n  if (Thread.currentThread().isInterrupted()) {\n    throw new QueryInterruptedException(\"Query cancelled\"); // treat as cancellation\n  }\n  throw e;\n}","preventionTips":["Preserve the interrupt flag; never swallow InterruptedException without re-interrupting","Map interrupted reads to your operation's cancellation path, not generic IO failure","Avoid interrupting worker threads for non-cancellation reasons","Fully consume or properly cancel HTTP responses so streams don't block waiting for bytes"],"tags":["http","interruption","stream","concurrency"],"backgroundTag":"request-timeout","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}