apache/kafka · error · java.lang.IllegalArgumentException

Invalid negative offset

Error message

Invalid negative offset

What it means

IllegalArgumentException from the OffsetAndMetadata constructor when the offset to be committed is negative. Offsets are non-negative positions in a partition; a negative value cannot represent a real committed position and would corrupt offset state on the broker.

Source

Thrown at clients/src/main/java/org/apache/kafka/clients/consumer/OffsetAndMetadata.java:52

    private final long offset;
    private final String metadata;

    // We use null to represent the absence of a leader epoch to simplify serialization.
    // I.e., older serializations of this class which do not have this field will automatically
    // initialize its value to null.
    private final Integer leaderEpoch;

    /**
     * Construct a new OffsetAndMetadata object for committing through {@link KafkaConsumer}.
     *
     * @param offset The offset to be committed
     * @param leaderEpoch Optional leader epoch of the last consumed record
     * @param metadata Non-null metadata
     */
    public OffsetAndMetadata(long offset, Optional<Integer> leaderEpoch, String metadata) {
        if (offset < 0)
            throw new IllegalArgumentException("Invalid negative offset");

        this.offset = offset;
        this.leaderEpoch = leaderEpoch.orElse(null);

        // The server converts null metadata to an empty string. So we store it as an empty string as well on the client
        // to be consistent.
        this.metadata = Objects.requireNonNullElse(metadata, OffsetFetchResponse.NO_METADATA);
    }

    /**
     * Construct a new OffsetAndMetadata object for committing through {@link KafkaConsumer}.
     * @param offset The offset to be committed
     * @param metadata Non-null metadata
     */
    public OffsetAndMetadata(long offset, String metadata) {
        this(offset, Optional.empty(), metadata);
    }

View on GitHub (pinned to c31c9215e1)

Solutions

  1. Guard the offset before constructing OffsetAndMetadata: skip commit if offset < 0.
  2. Replace sentinel -1 logic with OptionalLong.empty() / a no-op commit path when no offset exists.
  3. Trace where the negative value originates (position(), seek(), or a manual offset map) and correct the source.

Example fix

// before
consumer.commitSync(Collections.singletonMap(tp,
    new OffsetAndMetadata(currentPosition))); // currentPosition == -1

// after
if (currentPosition >= 0) {
    consumer.commitSync(Collections.singletonMap(tp,
        new OffsetAndMetadata(currentPosition)));
}
Defensive patterns

Strategy: validation

Validate before calling

// OffsetAndMetadata requires offset >= 0; clamp or reject negatives upstream
if (offset < 0) {
    throw new IllegalArgumentException("Cannot commit a negative offset (got " + offset + ")");
}
consumer.commitSync(Collections.singleton(tp, new OffsetAndMetadata(offset, leaderEpoch, metadata)));

Try / catch

try {
    new OffsetAndMetadata(offset, leaderEpoch, metadata);
} catch (IllegalArgumentException e) {
    if ("Invalid negative offset".equals(e.getMessage())) {
        // skip the commit for this partition or recompute offset from consumer.position(tp)
    }
    throw e;
}

Prevention

When it happens

Trigger: Calling new OffsetAndMetadata(offset, ...) or KafkaConsumer.commitSync with an offset that is -1 or otherwise negative, often because a lookup returned a sentinel/no-offset value.

Common situations: Using -1 or a NOT_FOUND sentinel to mean "no offset yet" and passing it directly; arithmetic that underflows when position() is unavailable (e.g. no assignment, empty partition); converting an unset long offset without a guard.

Related errors


AI-assisted analysis of apache/kafka@c31c9215e1 (2026-08-03). Data as JSON: /data/errors/c597cf296973bd6c.json. Report an issue: GitHub.