apache/kafka · error · IllegalArgumentException

MaxPollRecords must be strictly superior to 0

Error message

MaxPollRecords must be strictly superior to 0

What it means

Thrown by MockConsumer.setMaxPollRecords when the supplied value is less than 1. maxpoll records controls how many records a single poll returns; zero or negative is meaningless and would break poll loops. The mock validates this so tests catch configuration errors immediately rather than producing odd poll behavior.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/MockConsumer.java:395

     */
    public synchronized void addRecord(ConsumerRecord<K, V> record) {
        ensureNotClosed();
        TopicPartition tp = new TopicPartition(record.topic(), record.partition());
        Set<TopicPartition> currentAssigned = this.subscriptions.assignedPartitions();
        if (!currentAssigned.contains(tp))
            throw new IllegalStateException("Cannot add records for a partition that is not assigned to the consumer");
        List<ConsumerRecord<K, V>> recs = records.computeIfAbsent(tp, k -> new ArrayList<>());
        recs.add(record);
    }

    /**
     * Sets the maximum number of records returned in a single call to {@link #poll(Duration)}.
     *
     * @param maxPollRecords the max.poll.records.
     */
    public synchronized void setMaxPollRecords(long maxPollRecords) {
        if (maxPollRecords < 1) {
            throw new IllegalArgumentException("MaxPollRecords must be strictly superior to 0");
        }
        this.maxPollRecords = maxPollRecords;
    }

    /**
     * Sets an exception to throw when {@link #poll(Duration)} is called.
     *
     * @param exception the exception to throw
     */
    public synchronized void setPollException(KafkaException exception) {
        this.pollException = exception;
    }

    /**
     * Sets an exception to throw when offset-related methods are called.
     *
     * @param exception the exception to throw
     */

View on GitHub (pinned to 996fb4585a)

Solutions

  1. Pass a value >= 1 (typical values match real max.poll.records, e.g. 500).
  2. Validate the source config with a minimum bound before forwarding to setMaxPollRecords.
  3. Default to a sane positive constant (e.g. 500) when config is missing.

Example fix

// before
mockConsumer.setMaxPollRecords(0);

// after
mockConsumer.setMaxPollRecords(500);
Defensive patterns

Strategy: validation

Validate before calling

if (maxPollRecords < 1) throw new IllegalArgumentException("maxPollRecords must be >= 1");
mockConsumer.setMaxPollRecords(maxPollRecords);

Type guard

static boolean isValidMaxPoll(long v) {
    return v >= 1;
}

Try / catch

try {
    mockConsumer.setMaxPollRecords(requested);
} catch (IllegalArgumentException e) {
    if ("MaxPollRecords must be strictly superior to 0".equals(e.getMessage())) {
        mockConsumer.setMaxPollRecords(500); // safe default
    } else throw e;
}

Prevention

When it happens

Trigger: Calling setMaxPollRecords(0) or a negative value; computing the value from config that defaulted to 0; test parameterization with a 0 entry.

Common situations: Tests parameterizing max.poll.records across a range that includes 0; config loader returning 0 for an unset key; refactor that changed the type from Optional<Long> to a primitive long defaulting to 0.

Related errors


AI-assisted analysis of apache/kafka@996fb4585a (2026-08-11). Data as JSON: /api/errors/64dfdfcfe1f005f0. Report an issue: GitHub.