You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jira@kafka.apache.org by "Ritika Reddy (Jira)" <ji...@apache.org> on 2026/09/29 16:28:00 UTC
[jira] [Created] (KAFKA-21181) Transaction coordinator could return INVALID_TXN_STATE from stale cache after losing __transaction_state leadership
Ritika Reddy created KAFKA-21181:
------------------------------------
Summary: Transaction coordinator could return INVALID_TXN_STATE from stale cache after losing __transaction_state leadership
Key: KAFKA-21181
URL: https://issues.apache.org/jira/browse/KAFKA-21181
Project: Kafka
Issue Type: Bug
Affects Versions: 4.3.0, 4.2.0
Reporter: Ritika Reddy
Assignee: Ritika Reddy
Fix For: 4.3.0, 4.2.0
When a broker loses leadership of a __transaction_state partition, its TransactionStateManager keeps the partition's cache entry until TransactionCoordinator.onResignation runs. In BrokerMetadataPublisher.onMetadataUpdate, that happens after replicaManager.applyDelta and after the group coordinator update. So there's a window in which the broker is already a follower for the partition but still answers coordinator requests from its old cache.
TransactionStateManager.getAndMaybeAddTransactionState (trunk lines 400-421) only checks loadingPartitions and transactionMetadataCache; it never checks that the broker still leads the partition. Answers that require a log write are safe, because the acks=-1 append fails with NOT_LEADER_OR_FOLLOWER, which is mapped to NOT_COORDINATOR. Answers decided purely from the cache are not.
With TV2 this surfaces as a fatal error for the producer:
1. Transaction N commits on coordinator A. The cache on A holds COMPLETE_COMMIT at epoch E, and the client now has epoch E.
2. Leadership of the __transaction_state partition moves to broker B. B loads the partition, and the partition leaders' implicit AddPartitionsToTxn for transaction N+1 go to B, which moves the transaction to ONGOING.
3. The client hasn't had any reason to rediscover the coordinator: under TV2 its first coordinator request in the transaction is EndTxn. So it sends EndTxn(COMMIT, E) to A.
4. A is already a follower but hasn't resigned yet. It answers from the cache: COMPLETE_COMMIT + COMMIT at the current epoch is not a retry, so it returns INVALID_TXN_STATE without writing to the log:
TransactionalId: <id>'s state is COMPLETE_COMMIT, but received transaction marker result to send: COMMIT
5. The producer treats INVALID_TXN_STATE as fatal. The transaction on B stays ONGOING until it times out.
The correct response is NOT_COORDINATOR, which would make the client rediscover B and commit. We've seen gaps of several seconds between the broker becoming follower and resigning, and in one case ~37 s, with no broker pause involved.
Other cache-only answers are exposed the same way, for example PRODUCER_FENCED / INVALID_PRODUCER_ID_MAPPING, the verify-only AddPartitionsToTxn path, and the "partitions already added" shortcut.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)