{"record":{"id":"14ebc06e55c2f95b","repo":"apache/pulsar","slug":"transaction-pending-ack-replay-error-with-illegal","errorCode":null,"errorMessage":"Transaction pending ack replay error with illegal state : ","messagePattern":"Transaction pending ack replay error with illegal state : ","errorType":"validation","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/transaction/pendingack/impl/MLPendingAckReplyCallBack.java","lineNumber":123,"sourceCode":"                            if (pendingAckMetadata.getAckSetsCount() > 0) {\n                                ackSets = new long[pendingAckMetadata.getAckSetsCount()];\n                                for (int i = 0; i < pendingAckMetadata.getAckSetsCount(); i++) {\n                                    ackSets[i] = pendingAckMetadata.getAckSetAt(i);\n                                }\n                            } else {\n                                ackSets = new long[0];\n                            }\n                            Position position =\n                                    AckSetStateUtil.createPositionWithAckSet(pendingAckMetadata.getLedgerId(),\n                                            pendingAckMetadata.getEntryId(), ackSets);\n                            positions.add(new MutablePair<>(position, pendingAckMetadata.getBatchSize()));\n                        }\n                    });\n                    pendingAckHandle.handleIndividualAckRecover(txnID, positions);\n                }\n                break;\n            default:\n                throw new IllegalStateException(\"Transaction pending ack replay \"\n                        + \"error with illegal state : \" + pendingAckMetadataEntry.getPendingAckOp());\n\n        }\n    }\n}","sourceCodeStart":105,"sourceCodeEnd":128,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/transaction/pendingack/impl/MLPendingAckReplyCallBack.java#L105-L128","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":"// Before replay, ensure broker versions are uniform:\n// check cluster version consistency and that the pending-ack ledger is readable\n// No in-process pre-check exists; validate via ledger entry read before replay.","typeGuard":null,"tryCatchPattern":"try {\n    callBack.handleMetadataEntry(entry);\n} catch (IllegalStateException e) {\n    log.error(\"Pending-ack replay failed on entry: {}\", entry.getEntryId(), e);\n    // halt replay and inspect the pending-ack ledger; do not continue with partial state\n    throw new TransactionPendingAckReplayException(e);\n}","preventionTips":["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"],"tags":["transaction","replay","illegal-state"],"backgroundTag":"transaction-replay-illegal-state","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}