apache/hadoop · error · IllegalArgumentException

Buffer has no data left.

Error message

Buffer has no data left.

What it means

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?').

Source

Thrown at hadoop-common-project/hadoop-common/src/main/java/org/apache/hadoop/net/SocketIOWithTimeout.java:131

   * It waits up to the specified timeout. If the channel is 
   * not read before the timeout, SocketTimeoutException is thrown.
   * 
   * @param buf buffer for IO
   * @param ops Selection Ops used for waiting. Suggested values: 
   *        SelectionKey.OP_READ while reading and SelectionKey.OP_WRITE while
   *        writing. 
   *        
   * @return number of bytes read or written. negative implies end of stream.
   * @throws IOException
   */
  int doIO(ByteBuffer buf, int ops) throws IOException {
    
    /* For now only one thread is allowed. If user want to read or write
     * from multiple threads, multiple streams could be created. In that
     * case multiple threads work as well as underlying channel supports it.
     */
    if (!buf.hasRemaining()) {
      throw new IllegalArgumentException("Buffer has no data left.");
      //or should we just return 0?
    }

    while (buf.hasRemaining()) {
      if (closed) {
        return -1;
      }

      try {
        int n = performIO(buf);
        if (n != 0) {
          // successful io or an error.
          return n;
        }
      } catch (IOException e) {
        if (!channel.isOpen()) {
          closed = true;
        }

View on GitHub (pinned to 2add963021)

Solutions

  1. Reset the buffer each iteration: clear() before reads, flip() or rewind() before writes as appropriate
  2. Skip or return early when !buf.hasRemaining() instead of calling the API
  3. Unit-test the loop against partial reads/writes so positions are always valid

Example fix

// before
while (!done) { in.read(buf); } // buf never cleared -> throws once drained

// after
while (!done) {
  buf.clear();
  int n = in.read(buf);
  if (n < 0) break;
  buf.flip();
  consume(buf);
}
Defensive patterns

Strategy: validation

Validate before calling

if (!buf.hasRemaining()) {
  buf.clear(); // or skip the call if there is nothing to transfer
}
in.read(buf);

Type guard

static boolean bufferReadyForIo(ByteBuffer buf) {
  return buf != null && buf.hasRemaining();
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of apache/hadoop@2add963021 (2026-08-22). Data as JSON: /api/errors/191a0823a527e92b. Report an issue: GitHub.