apache/pulsar · error · IllegalArgumentException

maxMessages must be >= 0

Error message

maxMessages must be >= 0

What it means

The private BatchingPolicy constructor (reached via its builder) requires maxMessages to be non-negative, since it caps how many messages may be accumulated in a single batch. A negative value is nonsensical as a cap, so the library throws IllegalArgumentException at construction time.

Source

Thrown at pulsar-client-api-v5/src/main/java/org/apache/pulsar/client/api/v5/config/BatchingPolicy.java:57

    private static final Duration DEFAULT_MAX_PUBLISH_DELAY = Duration.ofMillis(1);
    private static final int DEFAULT_MAX_MESSAGES = 1000;
    private static final MemorySize DEFAULT_MAX_SIZE = MemorySize.ofKilobytes(128);

    private static final BatchingPolicy DISABLED =
            new BatchingPolicy(false, DEFAULT_MAX_PUBLISH_DELAY, DEFAULT_MAX_MESSAGES, DEFAULT_MAX_SIZE);

    private final boolean enabled;
    private final Duration maxPublishDelay;
    private final int maxMessages;
    private final MemorySize maxSize;

    private BatchingPolicy(boolean enabled, Duration maxPublishDelay, int maxMessages, MemorySize maxSize) {
        if (maxPublishDelay == null) {
            maxPublishDelay = DEFAULT_MAX_PUBLISH_DELAY;
        }
        Objects.requireNonNull(maxSize, "maxSize must not be null");
        if (maxMessages < 0) {
            throw new IllegalArgumentException("maxMessages must be >= 0");
        }
        if (maxSize.bytes() < 0) {
            throw new IllegalArgumentException("maxBytes must be >= 0");
        }
        this.enabled = enabled;
        this.maxPublishDelay = maxPublishDelay;
        this.maxMessages = maxMessages;
        this.maxSize = maxSize;
    }

    /**
     * @return whether batching is enabled
     */
    public boolean enabled() {
        return enabled;
    }

    /**

View on GitHub (pinned to 820761864e)

Solutions

  1. Pass 0 or a positive number to maxMessages; use 0 if you want to disable message-count-based batching.
  2. If -1 is your 'unset' sentinel, map it to the builder default (omit the maxMessages call).
  3. Validate the value at config load time: Math.max(0, configuredValue) or reject the config.

Example fix

// before
BatchingPolicy bp = BatchingPolicy.builder()
    .maxMessages(-1) // IllegalArgumentException
    .build();

// after
BatchingPolicy bp = BatchingPolicy.builder()
    .maxMessages(1000) // or omit to use the default
    .build();
Defensive patterns

Strategy: validation

Validate before calling

if (maxMessages < 0) {
    throw new IllegalArgumentException("maxMessages must be >= 0, got: " + maxMessages);
}
BatchingPolicy bp = BatchingPolicy.builder().maxMessages(maxMessages).build();

Type guard

static boolean isValidMaxMessages(int v) { return v >= 0; }

Try / catch

try {
    bp = BatchingPolicy.builder().maxMessages(cfg).build();
} catch (IllegalArgumentException e) {
    log.warn("Invalid maxMessages, using default batching", e);
    bp = BatchingPolicy.builder().build();
}

Prevention

When it happens

Trigger: Calling BatchingPolicy.builder().maxMessages(n) with n < 0, or invoking the private constructor via a factory with a negative maxMessages argument, e.g. maxMessages(-1).

Common situations: Computing the batch size from a formula that can go negative (e.g. remaining quota subtraction); parsing a config value with a stray minus sign; a defaulting routine that uses -1 as a sentinel for 'unset' instead of 0 or Optional.

Understand the failure class

Background: "Invalid configuration value" and "Unsupported/Unknown setting value" errors: why libraries reject your config strings, numbers, and types — this error's family across 30 libraries.

Related errors


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