apache/pulsar · error · IllegalStateException

Transaction pending ack replay error with illegal state :

Error message

Transaction pending ack replay error with illegal state : 

What it means

During transaction pending-ack replay, MLPendingAckReplyCallBack.handleMetadataEntry applies each replayed pending-ack metadata operation (e.g. commit, abort, individual ack recovery) to the pending ack handle. A switch over the operation type has no default case matching, meaning the log contains a PendingAckOp unknown/unexpected for this state. It throws IllegalStateException to fail-fast rather than silently dropping replay operations, which would corrupt pending-ack state.

Solutions

  1. Inspect the pendingAckOp value in the metadata entry and confirm which broker version wrote it
  2. Verify all brokers in the cluster run a version that understands all PendingAckOp types present in the log
  3. Check the pending-ack ledger for corruption; if entries are corrupt, follow Pulsar runBookie/consistency recovery procedures for that managed ledger
  4. If caused by a version skew, roll forward (or uniformly roll back) all brokers, then replay
Defensive patterns

Strategy: try-catch

Validate before calling

// Before replay, ensure broker versions are uniform:
// check cluster version consistency and that the pending-ack ledger is readable
// No in-process pre-check exists; validate via ledger entry read before replay.

Try / catch

try {
    callBack.handleMetadataEntry(entry);
} catch (IllegalStateException e) {
    log.error("Pending-ack replay failed on entry: {}", entry.getEntryId(), e);
    // halt replay and inspect the pending-ack ledger; do not continue with partial state
    throw new TransactionPendingAckReplayException(e);
}

Prevention

When it happens

Trigger: Replaying a transaction pending-ack metadata entry whose PendingAckOp is not one of the handled cases — i.e. a corrupt or truncated bookkeeper entry, or a PendingAckOp written by a newer broker version being replayed by an older one.

Common situations: Upgrading/downgrading brokers in a cluster where the pending-ack log format changed; corrupted ledger entries after an unclean shutdown or disk issue; replaying a transaction log snapshot produced by different code paths.

Related errors


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

Appendix: source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/transaction/pendingack/impl/MLPendingAckReplyCallBack.java:123

                            if (pendingAckMetadata.getAckSetsCount() > 0) {
                                ackSets = new long[pendingAckMetadata.getAckSetsCount()];
                                for (int i = 0; i < pendingAckMetadata.getAckSetsCount(); i++) {
                                    ackSets[i] = pendingAckMetadata.getAckSetAt(i);
                                }
                            } else {
                                ackSets = new long[0];
                            }
                            Position position =
                                    AckSetStateUtil.createPositionWithAckSet(pendingAckMetadata.getLedgerId(),
                                            pendingAckMetadata.getEntryId(), ackSets);
                            positions.add(new MutablePair<>(position, pendingAckMetadata.getBatchSize()));
                        }
                    });
                    pendingAckHandle.handleIndividualAckRecover(txnID, positions);
                }
                break;
            default:
                throw new IllegalStateException("Transaction pending ack replay "
                        + "error with illegal state : " + pendingAckMetadataEntry.getPendingAckOp());

        }
    }
}

View on GitHub (pinned to 820761864e)