apache/pulsar · error · IllegalArgumentException

Try to reserve/release memory failed, the param memorySize i

Error message

Try to reserve/release memory failed, the param memorySize is a negative value: ${memorySize}

What it means

MemoryLimitController tracks client-side memory usage; reserving or releasing a negative byte count would corrupt the accounting, so checkPositive throws IllegalArgumentException (and logs the error) whenever memorySize < 0. Called by reserveMemory, tryReserveMemory, forceReserveMemory and releaseMemory.

Source

Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/MemoryLimitController.java:89

            // We allow one request to go over the limit, to make the notification
            // path simpler and more efficient
            if (current > memoryLimit && memoryLimit > 0) {
                return false;
            }

            if (currentUsage.compareAndSet(current, newUsage)) {
                checkTrigger(current, newUsage);
                return true;
            }
        }
    }

    private static void checkPositive(long memorySize) {
        if (memorySize < 0) {
            String errorMsg = String.format("Try to reserve/release memory failed, the param memorySize"
                    + " is a negative value: %s", memorySize);
            log.error(errorMsg);
            throw new IllegalArgumentException(errorMsg);
        }
    }

    private void checkTrigger(long prevUsage, long newUsage) {
        if (newUsage >= triggerThreshold && prevUsage < triggerThreshold && !triggers.isEmpty()) {
            if (triggerRunning.compareAndSet(false, true)) {
                try {
                    for (Runnable trigger : triggers) {
                        trigger.run();
                    }
                } finally {
                    triggerRunning.set(false);
                }
            }
        }
    }

    public void reserveMemory(long size) throws InterruptedException {

View on GitHub (pinned to 820761864e)

Solutions

  1. Clamp computed sizes to >= 0 before calling reserveMemory/releaseMemory (Math.max(0, size)).
  2. Fix the size calculation that produces the negative value (check buffer position/remaining ordering).
  3. If releasing, pass the exact positive size that was originally reserved.

Example fix

// before
long size = afterOffset - beforeOffset;
controller.releaseMemory(size);
// after
long size = Math.max(0, afterOffset - beforeOffset);
controller.releaseMemory(size);
Defensive patterns

Strategy: validation

Validate before calling

long size = computeSize();
if (size < 0) throw new IllegalStateException("computed negative size");
memoryLimitController.reserveMemory(size);

Try / catch

try {
  controller.tryReserveMemory(size);
} catch (IllegalArgumentException e) {
  // negative size: fix size computation before retrying
}

Prevention

When it happens

Trigger: Calling any memory-limit API with a negative size, typically because a computed size (payload.remaining(), serialized size, difference of offsets) went negative due to an underflow or unhandled empty buffer.

Common situations: Custom producer interceptor computing sizes with int/long underflow; passing buffer.remaining() after the buffer was fully consumed; diff-based accounting (afterSize - beforeSize) on reordered callbacks.

Related errors


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/df389209a3f9f13d. Report an issue: GitHub.