apache/beam · error · IllegalStateException

There are different initial sequences detected

Error message

There are different initial sequences detected: %s and %s

What it means

SequenceRangeAccumulator.add() records which sequence was the first (initial) event of a key. If an element marked as an initial sequence is added while a different initialSequence is already stored, the accumulator's invariant is violated and it throws IllegalStateException. This guards against corrupted or merged-by-mistake combine state where events of different keys/sessions share one accumulator.

Solutions

  1. Ensure events are keyed correctly so all elements reaching one accumulator belong to the same initial sequence.
  2. If reusing accumulators, create a fresh SequenceRangeAccumulator per key instead of reusing instances.
  3. Fix custom addInput/mergeAccumulators logic to route by key before adding.
  4. Verify the isInitialSequence flag is only set for the true first event of the stream.

Example fix

// before
acc.add(42, ts, true); // acc.initialSequence == 7 -> IllegalStateException
// after
SequenceRangeAccumulator acc = SequenceRangeAccumulator.create(); // fresh accumulator for this key
acc.add(42, ts, true);
Defensive patterns

Strategy: validation

Validate before calling

// before adding
if (acc.hasInitialSequence() && acc.getInitialSequence() != sequence && isInitial) {
  throw new IllegalArgumentException("mismatched initial sequence " + sequence + " vs " + acc.getInitialSequence());
}

Type guard

static boolean canAccept(SequenceRangeAccumulator acc, long sequence, boolean isInitial) {
  return !isInitial || acc.getInitialSequence() == null || acc.getInitialSequence() == sequence;
}

Try / catch

try {
  acc.add(seq, ts, isInitial);
} catch (IllegalStateException e) {
  if (e.getMessage().startsWith("There are different initial sequences")) {
    throw new IllegalStateException("events of different keys reached one accumulator; fix keying", e);
  }
  throw e;
}

Prevention

When it happens

Trigger: Calling add(sequence, timestamp, isInitialSequence=true) on an accumulator whose initialSequence is already non-null and different from the new sequence; typically caused by mis-partitioned input feeding one accumulator events from multiple keys, or combining accumulators incorrectly in a custom CombineFn.

Common situations: Custom fanout or key-breaking in the Beam combine where accumulators are reused across keys; a bug in a custom mergeAccumulators/addInput; deterministic unit tests deliberately feeding conflicting initial sequences.

Understand the failure class

Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.

Related errors


AI-assisted analysis of apache/beam@12126d8942 (2026-09-13). Data as JSON: /api/errors/bb5c3921e31d2a5c. Report an issue: GitHub.

Appendix: source

Thrown at sdks/java/extensions/ordered/src/main/java/org/apache/beam/sdk/extensions/ordered/combiner/SequenceRangeAccumulator.java:61

    return a.isAfter(b) ? a : b;
  }

  /**
   * The tree contains a set of non-overlapping contiguous ranges, where the key is the lower
   * inclusive start of the range, left value of the pair is the inclusive end of the range and the
   * right value of the pair is the maximum timestamp in the range.
   *
   * <p>The maximum timestamp is critical for the correctness of the ordered processing. During the
   * merge process the merged range is assigned the maximum timestamp of the two ranges that created
   * this new range.
   */
  private final TreeMap<Long, Pair<Long, Instant>> data = new TreeMap<>();

  private @Nullable Long initialSequence = null;

  public void add(long sequence, Instant timestamp, boolean isInitialSequence) {
    if (isInitialSequence && this.initialSequence != null && sequence != this.initialSequence) {
      throw new IllegalStateException(
          "There are different initial sequences detected: "
              + initialSequence
              + " and "
              + sequence);
    }

    if (sequence == Long.MAX_VALUE) {
      // This is an invalid value and DoFns will not process this element. This will also allow
      // to produce a ContiguousSequenceRange with the exclusive end value.
      return;
    }

    if (isInitialSequence) {
      this.initialSequence = sequence;
      clearRangesBelowInitialSequence(sequence, timestamp);
    } else if (initialSequence != null && sequence <= initialSequence) {
      // No need to add anything lower than the initial sequence to the accumulator.
      return;

View on GitHub (pinned to 12126d8942)