{"record":{"id":"191a0823a527e92b","repo":"apache/hadoop","slug":"buffer-has-no-data-left","errorCode":null,"errorMessage":"Buffer has no data left.","messagePattern":"Buffer has no data left\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/SocketIOWithTimeout.java","lineNumber":131,"sourceCode":"   * It waits up to the specified timeout. If the channel is \n   * not read before the timeout, SocketTimeoutException is thrown.\n   * \n   * @param buf buffer for IO\n   * @param ops Selection Ops used for waiting. Suggested values: \n   *        SelectionKey.OP_READ while reading and SelectionKey.OP_WRITE while\n   *        writing. \n   *        \n   * @return number of bytes read or written. negative implies end of stream.\n   * @throws IOException\n   */\n  int doIO(ByteBuffer buf, int ops) throws IOException {\n    \n    /* For now only one thread is allowed. If user want to read or write\n     * from multiple threads, multiple streams could be created. In that\n     * case multiple threads work as well as underlying channel supports it.\n     */\n    if (!buf.hasRemaining()) {\n      throw new IllegalArgumentException(\"Buffer has no data left.\");\n      //or should we just return 0?\n    }\n\n    while (buf.hasRemaining()) {\n      if (closed) {\n        return -1;\n      }\n\n      try {\n        int n = performIO(buf);\n        if (n != 0) {\n          // successful io or an error.\n          return n;\n        }\n      } catch (IOException e) {\n        if (!channel.isOpen()) {\n          closed = true;\n        }","sourceCodeStart":113,"sourceCodeEnd":149,"githubUrl":"https://github.com/apache/hadoop/blob/2add9630210752f88ceb1bb74eb65e37bf41da8e/hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/SocketIOWithTimeout.java#L113-L149","documentation":"doIO(ByteBuffer, ops) is the core transfer loop of SocketIOWithTimeout. It requires buf.hasRemaining(); a buffer with position == limit has nothing to read into or write out, which is always a caller bug, so it throws IllegalArgumentException up front (the source even muses 'or should we just return 0?').","triggerScenarios":"Calling read(ByteBuffer)/write(ByteBuffer) on SocketInputStream/SocketOutputStream with an exhausted buffer — typically forgetting buffer.clear() after draining a read, or flip()/rewind before a write, inside a loop.","commonSituations":"ByteBuffer position/limit mismanagement in NIO read/write loops; reusing one shared buffer across iterations without resetting; partial-read loops that keep calling with the same consumed buffer.","solutions":["Reset the buffer each iteration: clear() before reads, flip() or rewind() before writes as appropriate","Skip or return early when !buf.hasRemaining() instead of calling the API","Unit-test the loop against partial reads/writes so positions are always valid"],"exampleFix":"// before\nwhile (!done) { in.read(buf); } // buf never cleared -> throws once drained\n\n// after\nwhile (!done) {\n  buf.clear();\n  int n = in.read(buf);\n  if (n < 0) break;\n  buf.flip();\n  consume(buf);\n}","handlingStrategy":"validation","validationCode":"if (!buf.hasRemaining()) {\n  buf.clear(); // or skip the call if there is nothing to transfer\n}\nin.read(buf);","typeGuard":"static boolean bufferReadyForIo(ByteBuffer buf) {\n  return buf != null && buf.hasRemaining();\n}","tryCatchPattern":null,"preventionTips":["clear()/flip() the buffer on every loop iteration","Add assertions for buffer positions in tests that exercise partial reads/writes"],"tags":["hadoop-common","network","nio","bytebuffer","java"],"backgroundTag":"empty-byte-buffer","analyzedSha":"2add9630210752f88ceb1bb74eb65e37bf41da8e","analyzedAt":"2026-08-22T19:55:07.957Z","schemaVersion":2},"datasetVersion":"2026-08-22T20:17:22.307Z"}