apache/rocketmq · error · IllegalArgumentException

Timeout must not be negative

Error message

Timeout must not be negative

What it means

DefaultLitePullConsumerImpl.poll(long timeout) throws IllegalArgumentException("Timeout must not be negative") when timeout < 0. poll() blocks up to timeout milliseconds waiting for a ConsumeRequest from the local cache; a negative timeout is meaningless for that wait and is rejected before any pulling occurs.

Source

Thrown at client/src/main/java/org/apache/rocketmq/client/impl/consumer/DefaultLitePullConsumerImpl.java:610

            throw new IllegalStateException("setAssignTag only can be called before start.");
        }
        setSubscriptionType(SubscriptionType.ASSIGN);
        topicToSubExpression.put(topic, subExpression);
    }

    private void maybeAutoCommit() {
        long now = System.currentTimeMillis();
        if (now >= nextAutoCommitDeadline) {
            commitAll();
            nextAutoCommitDeadline = now + defaultLitePullConsumer.getAutoCommitIntervalMillis();
        }
    }

    public synchronized List<MessageExt> poll(long timeout) {
        try {
            checkServiceState();
            if (timeout < 0) {
                throw new IllegalArgumentException("Timeout must not be negative");
            }

            if (defaultLitePullConsumer.isAutoCommit()) {
                maybeAutoCommit();
            }
            long endTime = System.currentTimeMillis() + timeout;

            ConsumeRequest consumeRequest = consumeRequestCache.poll(endTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);

            if (endTime - System.currentTimeMillis() > 0) {
                while (consumeRequest != null && consumeRequest.getProcessQueue().isDropped()) {
                    consumeRequest = consumeRequestCache.poll(endTime - System.currentTimeMillis(), TimeUnit.MILLISECONDS);
                    if (endTime - System.currentTimeMillis() <= 0) {
                        break;
                    }
                }
            }

View on GitHub (pinned to 293f588571)

Solutions

  1. Clamp computed timeouts: Math.max(0, remaining)
  2. Use a large positive value (or consumerTimeoutMillisWhenSuspend tuning) for long waits instead of -1
  3. Remember poll(0) is legal and returns immediately

Example fix

// before
long remain = deadline - System.currentTimeMillis();
List<MessageExt> msgs = consumer.poll(remain);

// after
long remain = Math.max(0, deadline - System.currentTimeMillis());
List<MessageExt> msgs = consumer.poll(remain);
Defensive patterns

Strategy: validation

Validate before calling

long safeTimeout = Math.max(0, timeout);
List<MessageExt> msgs = consumer.poll(safeTimeout);

Prevention

When it happens

Trigger: consumer.poll(-1); passing a computed timeout that underflows (e.g. deadline - System.currentTimeMillis() after the deadline passed).

Common situations: Reusing Kafka poll(-1) idiom (infinite block) — RocketMQ does not support it; arithmetic on elapsed time producing negative values.

Understand the failure class

Related errors


AI-assisted analysis of apache/rocketmq@293f588571 (2026-08-14). Data as JSON: /api/errors/54d0946837c329c2. Report an issue: GitHub.