This page is meant as a template for writing a KIP. To create a KIP choose Tools->Copy on this page and modify with your content and replace the heading with the next KIP number and a description of your issue. Replace anything in italics with your own description.

Status

Current stateUnder Discussion

Discussion thread: here [Change the link from the KIP proposal email archive to your own email thread]

JIRA: KAFKA-20029

Please keep the discussion on the mailing list rather than commenting on the wiki (wiki discussions get unwieldy fast).

Motivation

Internal topics in Kafka, specifically __transaction_state, __consumer_offsets, and the recently introduced __share_group_state (KIP-932),
rely on a specific hashing mechanism to route keys (transaction IDs, group IDs) to partitions.

For example, the routing logic for the Transaction Coordinator maps a Transaction ID to a specific partition of __transaction_state using the following logic:

Utils.abs(transactionId.hashCode()) % transactionTopicPartitionCount

This logic creates a strict dependency on the transactionTopicPartitionCount.
If the number of partitions changes (e.g., expanding from 50 to 150), the mapping logic changes immediately.

While the Kafka documentation advises against modifying these internal topics,
there is currently no hard guardrail preventing this operation via the Admin API  CreatePartitions.

The Problem: Split-Brain and Data Inconsistency

Allowing dynamic partition expansion for these internal topics leads to critical availability and correctness issues, including split-brain scenarios, orphan transactions, and hanging transactions.

Here is a breakdown of the race condition identified during an expansion scenario (e.g., 50 -> 150 partitions):

  1. Metadata Inconsistency: During the expansion, the metadata cache updates are not atomic across all nodes.

  2. Split-Brain View:

  3. Routing Divergence: A producer sending FindCoordinator for Transaction ID "A" may be routed to Partition 130 or Partition 27 depending on which broker handles the request.

  4. Orphan/Hanging Transactions:

This issue is not limited to __transaction_state :

Currently, this is only prevented by documentation "advice," which is insufficient to prevent critical human errors or automated misconfigurations.


Public Interfaces

Proposed Changes

We propose to enforce a validation check in the Controller API layer to reject CreatePartitions requests targeting internal topics,
while allowing other valid requests in the same batch to proceed.

1. Configuration

We will introduce a new configuration to control this guardrail.

2. Validation in ControllerApis

The validation logic will be implemented in kafka.server.ControllerApis to "fail fast" before the request reaches the Raft layer or Metadata cache.

In ControllerApis.handleCreatePartitions:

  1. The controller will iterate through the list of topics in the CreatePartitionsRequest.

  2. It will identify internal topics using Topic.isInternal(name).

  3. If controller.allow.internal.topic.modification is false:

This approach ensures that an accidental inclusion of an internal topic in a bulk operation does not fail the entire batch (supporting partial failures),
aligning with standard Kafka Admin API behavior.

Compatibility, Deprecation, and Migration Plan

Compatibility

Deprecation

Migration Plan

Test Plan

Rejected Alternatives

1. Alternative Partitioning Strategies (e.g., Consistent Hashing, Rendezvous Hashing)

A theoretically more robust approach would be to adopt a partitioning strategy that minimizes key redistribution, such as Consistent Hashing. rejected reasons are:

2. Automatic Data Redistribution

We considered allowing the expansion and automatically redistributing data to new partitions. rejected reasons are:

3. Validation in ReplicationControlManager (Deep Validation)

We considered validating deep inside the metadata layer. rejected reason is:

4. Client-Side or Tool-Level Validation Only

We considered implementing the restriction solely in client-side tools (e.g., kafka-topics.sh) or the AdminClient SDK. rejected reasons are: