apache/pulsar · error · IllegalArgumentException

first delta must be > 0, got

Error message

first delta must be > 0, got ${deltas.get(0)}

What it means

IllegalArgumentException thrown by the compact constructor of the SequenceKeysDeltas record in Option.java. The library enforces that a sequence-key delta list starts with a strictly positive first delta, because the first delta establishes the initial offset of the sequence; a zero or negative value would produce an invalid or ambiguous starting sequence.

Solutions

  1. Ensure the first element of the deltas list is strictly positive before constructing SequenceKeysDeltas
  2. Fix the delta-computation logic so the first delta is derived as (firstKey - baseKey) with baseKey < firstKey
  3. Pre-validate inputs with an explicit check and produce a domain-specific error instead of a raw IllegalArgumentException

Example fix

// before
SequenceKeysDeltas d = new SequenceKeysDeltas(List.of(0L, 3L)); // throws
// after
List<Long> deltas = computeDeltas(keys);
if (deltas.isEmpty() || deltas.get(0) <= 0) {
    throw new IllegalStateException("first delta must be positive, got " + (deltas.isEmpty() ? "none" : deltas.get(0)));
}
SequenceKeysDeltas d = new SequenceKeysDeltas(deltas);
Defensive patterns

Strategy: validation

Validate before calling

if (deltas == null || deltas.isEmpty()) throw new IllegalArgumentException("deltas required");
if (deltas.get(0) <= 0) throw new IllegalArgumentException("first delta must be > 0");
for (int i = 1; i < deltas.size(); i++) { if (deltas.get(i) < 0) throw new IllegalArgumentException("negative delta at " + i); }

Type guard

static boolean isValidDeltas(List<Long> deltas) {
    return deltas != null && !deltas.isEmpty() && deltas.get(0) > 0
        && deltas.stream().skip(1).allMatch(d -> d >= 0);
}

Prevention

When it happens

Trigger: Constructing SequenceKeysDeltas (directly or via a metadata API that builds one) with a list whose first element is <= 0, e.g. List.of(0L, 5L) or a computed first delta of 0 when two consecutive keys are equal.

Common situations: Passing empty or degenerate delta lists computed from log/event sequences; off-by-one in delta computation producing 0 for the first entry; deserializing user-supplied delta arrays without pre-validation.

Related errors


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

Appendix: source

Thrown at pulsar-metadata/src/main/java/org/apache/pulsar/metadata/api/Option.java:94

     * <p>The {@code Stat} returned from the {@code put} carries the actual generated path. Pair
     * with {@link MetadataStore#subscribeSequence} to receive notifications as new sequence keys
     * are created.
     *
     * <p>Constraints: {@code deltas} must be non-empty, the first delta must be {@code > 0}, and
     * the rest must be {@code >= 0}. On Oxia a {@link PartitionKey} must also be provided.
     * Backends without native sequence-key support synthesize the same key format using a
     * sidecar counter document and CAS.
     *
     * @param deltas per-dimension increments
     */
    record SequenceKeysDeltas(List<Long> deltas) implements Option {

        public SequenceKeysDeltas {
            if (deltas == null || deltas.isEmpty()) {
                throw new IllegalArgumentException("SequenceKeysDeltas requires at least one delta");
            }
            if (deltas.get(0) <= 0) {
                throw new IllegalArgumentException("first delta must be > 0, got " + deltas.get(0));
            }
            for (int i = 1; i < deltas.size(); i++) {
                if (deltas.get(i) < 0) {
                    throw new IllegalArgumentException(
                            "delta at index " + i + " must be >= 0, got " + deltas.get(i));
                }
            }
            deltas = List.copyOf(deltas);
        }
    }
}

View on GitHub (pinned to 820761864e)