apache/pulsar · error · IllegalArgumentException
SequenceKeysDeltas requires at least one delta
Error message
SequenceKeysDeltas requires at least one delta
What it means
Option.SequenceKeysDeltas is a record representing per-dimension increments for a sequence subscription; its compact constructor validates the input. It throws IllegalArgumentException('SequenceKeysDeltas requires at least one delta') when constructed with a null or empty delta list, since a sequence advance must move at least the first dimension.
Source
Thrown at pulsar-metadata/src/main/java/org/apache/pulsar/metadata/api/Option.java:91
* {@code prefix-{seq0}-{seq1}-...} where each sequence is zero-padded 20-digit decimal and
* each dimension increments atomically by its delta.
*
* <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)
Solutions
- Ensure the delta list has at least one element before constructing, e.g. guard with List.isEmpty().
- Provide a default first delta (>= 1) when no dimension state is available.
- Fix upstream logic that produces empty delta lists so callers never construct the option with no deltas.
Example fix
// before
Option opt = new SequenceKeysDeltas(computedDeltas); // may be empty
// after
if (computedDeltas == null || computedDeltas.isEmpty()) {
computedDeltas = List.of(1L); // minimal valid advance
}
Option opt = new SequenceKeysDeltas(computedDeltas); Defensive patterns
Strategy: validation
Validate before calling
if (deltas == null || deltas.isEmpty()) {
throw new IllegalArgumentException("SequenceKeysDeltas needs at least one delta");
}
Option opt = new SequenceKeysDeltas(deltas); Type guard
boolean validDeltas(List<Long> deltas) {
return deltas != null && !deltas.isEmpty() && deltas.get(0) > 0
&& deltas.stream().skip(1).allMatch(d -> d >= 0);
} Try / catch
try {
Option opt = new SequenceKeysDeltas(deltas);
} catch (IllegalArgumentException e) {
log.warn("Invalid deltas: {}", e.getMessage());
opt = new SequenceKeysDeltas(List.of(1L));
} Prevention
- Guard delta lists for non-empty content and positive first element before constructing
- Add unit tests covering empty/null delta inputs at the producer of the list
- Prefer a factory method that normalizes empty input instead of raw record construction
When it happens
Trigger: new SequenceKeysDeltas(List.of()) or new SequenceKeysDeltas(null), or programmatically building deltas from an empty collection before passing them to subscribeSequence.
Common situations: Code computing deltas from variable-dimension state that produced zero entries; deserializing a malformed/empty options payload; copy-paste building an empty list placeholder.
Related errors
- Sequence subscriptions not supported by this store
- Timeout during delete operation
- Timeout during close operation
- Timeout during open-cursor operation
- Timeout during delete-cursors operation
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/391d0be9d525f8bb.
Report an issue: GitHub.