bumptech/glide · error · IllegalStateException

This BufferQueue has already been consumed

Error message

This BufferQueue has already been consumed

What it means

Thrown by the Cronet integration's BufferQueue.markCoalesced() when the queue has already been consumed once. BufferQueue uses an AtomicBoolean (isCoalesced) flipped from false to true via compareAndSet; a second coalesce/consume attempt fails the CAS and aborts, because the underlying buffers have already been drained.

Source

Thrown at integration/cronet/src/main/java/com/bumptech/glide/integration/cronet/BufferQueue.java:133

    } else if (buffers.size() == 1) {
      return buffers.remove();
    } else {
      int size = 0;
      for (ByteBuffer buffer : buffers) {
        size += buffer.remaining();
      }
      ByteBuffer result = ByteBuffer.allocateDirect(size);
      while (!buffers.isEmpty()) {
        result.put(buffers.remove());
      }
      result.flip();
      return result;
    }
  }

  private void markCoalesced() {
    if (!isCoalesced.compareAndSet(false, true)) {
      throw new IllegalStateException("This BufferQueue has already been consumed");
    }
  }
}

View on GitHub (pinned to eb14a895d8)

Solutions

  1. Consume each BufferQueue exactly once; cache the resulting ByteBuffer if you need the data in multiple places.
  2. If multiple consumers need the body, coalesce once and copy/distribute the resulting buffer.
  3. Ensure interceptors do not double-read the body; wrap with a single read-and-broadcast pattern.
  4. Reset the request so a fresh BufferQueue is produced for a true retry.

Example fix

// before
val body1 = queue.coalesceToBuffer()
val body2 = queue.coalesceToBuffer() // throws: already consumed

// after
val body = queue.coalesceToBuffer()
body.rewind()
val copy = body.duplicate() // share without re-consuming
Defensive patterns

Strategy: validation

Validate before calling

// Track consumption; read each BufferQueue exactly once.
var consumed = false
fun readOnce(queue: BufferQueue): ByteBuffer {
  check(!consumed) { "BufferQueue already consumed" }
  consumed = true
  return queue.coalesceToBuffer()
}

Try / catch

// If double-reads are possible, catch and recover by retrying the request.
try {
  body = queue.coalesceToBuffer()
} catch (e: IllegalStateException) {
  // re-issue the request to obtain a fresh BufferQueue
  requestAgain()
}

Prevention

When it happens

Trigger: coalesceToBuffer() (or any path calling markCoalesced) is invoked more than once on the same BufferQueue instance, e.g. reading the Cronet response body twice.

Common situations: An interceptor or middleware that re-reads the Cronet response body; retrying a request that reuses the same buffer queue; a logging layer that buffers the body for inspection then the real consumer reads it again.

Related errors


AI-assisted analysis of bumptech/glide@eb14a895d8 (2026-08-14). Data as JSON: /api/errors/474e63f99b128b54. Report an issue: GitHub.