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.
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)
Solutions
- Inspect the pendingAckOp value in the metadata entry and confirm which broker version wrote it
- Verify all brokers in the cluster run a version that understands all PendingAckOp types present in the log
- Check the pending-ack ledger for corruption; if entries are corrupt, follow Pulsar runBookie/consistency recovery procedures for that managed ledger
- 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
- Keep all brokers on the same Pulsar version during rolling upgrades
- Enable managed-ledger integrity checks for pending-ack ledgers
- Back up transaction/pending-ack ledgers before upgrades
- Watch broker logs during replay and halt on first illegal-state error to limit corruption
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
- Transaction recover tracker`
- Invalid txnId key:
- Configuration field 'transactionPendingAckBatchedWriteMaxRec
- Configuration field 'transactionPendingAckBatchedWriteMaxSiz
- The schema is not a KeyValueSchema
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/14ebc06e55c2f95b.
Report an issue: GitHub.