apache/druid · error · IllegalStateException

Cannot exceed pre-configured maximum size

Error message

Cannot exceed pre-configured maximum size

What it means

DefaultBlockingPool.offer() returns an object to the pool only when the pool is below maxSize. Exceeding the pre-configured maximum means the pool's invariant (total objects <= maxSize) would be violated, so it throws ISE.

Solutions

  1. Ensure each taken object is offered back exactly once
  2. Only offer objects that were taken from this pool
  3. Audit code paths that duplicate releases (finally blocks plus explicit release)
  4. Increase maxSize only if the pool legitimately needs more capacity

Example fix

// before
T obj = pool.take();
pool.offer(obj); pool.offer(obj); // second offer over full pool -> ISE
// after
T obj = pool.take();
try { use(obj); } finally { pool.offer(obj); } // exactly once
Defensive patterns

Strategy: validation

Validate before calling

// offer only objects taken from the pool, exactly once
if (takenCount > 0 && !returned) { pool.offer(obj); returned = true; }

Try / catch

try {
  pool.offer(obj);
} catch (ISE e) {
  if ("Cannot exceed pre-configured maximum size".equals(e.getMessage())) { /* double-release; drop obj */ }
  else throw e;
}

Prevention

When it happens

Trigger: Calling offer() (via wrapObject) when the pool already holds maxSize objects — usually because an object was taken from the pool and offered back more than once, or a foreign object was offered while the pool is full.

Common situations: Double release of pooled buffers; pool misuse in custom code sharing DefaultBlockingPool; accounting bugs where taken counters were not decremented.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/3bc8a4beb7ed8114. Report an issue: GitHub.

Appendix: source

Thrown at processing/src/main/java/org/apache/druid/collections/DefaultBlockingPool.java:246

      lock.unlock();
    }
  }

  private void checkInitialized()
  {
    Preconditions.checkState(maxSize > 0, "Pool was initialized with limit = 0, there are no objects to take.");
  }

  private void offer(T theObject)
  {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
      if (objects.size() < maxSize) {
        objects.push(theObject);
        notEnough.signal();
      } else {
        throw new ISE("Cannot exceed pre-configured maximum size");
      }
    }
    finally {
      lock.unlock();
    }
  }
}

View on GitHub (pinned to 9b90983fd2)