Kafka KIP compatibility matrix
This matrix records what the tree claims about Kafka compatibility and where
the evidence for each claim is: one row per KIP that the roster in
kip_inventory lists or that any file under crates/
names, then the repository’s JVM differential evidence, which is the Kafka
on-disk log contract and the ApiVersions table every client negotiates
against.
KIP status
Every row comes from KIP_ANNOTATIONS in
api_catalog, and two sources decide
which rows have to be there. The generator scans crates/ for KIP-<n>
mentions, except the crate CHANGELOGs, and fails when a KIP is named without a
row here, so a compatibility claim cannot enter src/ without evidence beside
it. It also reads kip_inventory, the checked-in roster of
the KIPs the compatibility target covers, and fails when one of them has no
row – the direction the scan cannot see, because code that mentions its KIP in
no comment would otherwise go unadvertised here. A row for a KIP that neither
the roster nor crates/ names fails as well, and so does a row whose owner or
test does not exist, or a path::function entry naming a function the file does
not define.
- Status is
Implemented,Partial(the note says what is missing), orOut of scope(the note cites the decision). - Owner is the module that holds the behavior.
- Tests establish the status. A test under
src/is a unit or model test. - Kafka image is what the listed suites run against, read from each crate’s
BUILD.bazeldockermap and pinned below;in processmeans no suite in the row starts a Kafka container. - librdkafka is the non-JVM client evidence, and it is read from the row’s
own tests: a row is credited with a client exactly when a test it lists in
librdkafka_conformancedrives that client. The suite’sCLIENTStable names each one, and the cell names the test that ran it, so a row citing the test that drives only the librdkafka 2.x image is credited with that image and not the older one.
| KIP | Status | Contract | Owner | Tests | Kafka image | librdkafka | Notes |
|---|---|---|---|---|---|---|---|
| KIP-13 | Implemented | Producer and consumer byte-rate quotas | broker/ |
broker/broker/ |
in process | none | |
| KIP-32 | Implemented | Message timestamps in the v1 message set and the v2 batch | records-legacy/ |
log/log/broker/ |
cp_ |
none | The v0 and v1 message sets reach the wire only through Fetch v0-v3 and Produce v0-v2, which Kafka 4.x refuses and krabka serves only under the [runtime] key legacy_ (default off). Produce v3 and up still up-converts a legacy message set it carries. |
| KIP-48 | Implemented | Delegation tokens: create, renew, expire, describe and SCRAM token auth | broker/ |
broker/broker/ |
cp_, cp_ |
none | |
| KIP-62 | Implemented | Classic group state machine with the AwaitingSync stage | broker/ |
broker/broker/ |
in process | none | |
| KIP-73 | Implemented | Replication throttling through the leader and follower throttle keys | broker/ |
broker/ |
in process | none | The measured throttled-replication rate is published as krabka_ and krabka_, which stand for Kafka’s kafka. and its Follower twin, with krabka_ for the rounds the throttle held back entirely. Kafka delays a throttled fetch; krabka drops the partition from the round and the follower re-asks, so there is no throttle_ to attribute and the byte-rate is what says whether the throttle is biting. |
| KIP-74 | Implemented | Fetch response size limits: max_bytes and partition_ |
log/ |
log/log/broker/ |
in process | none | Only the first batch of a read can be larger than the budget, so a fetch always makes progress, and a read that the budget stops inside a segment does not go on into the next one. |
| KIP-98 | Implemented | Transactions and idempotent producers, with transactional-id expiry | broker/ |
broker/broker/broker/broker/broker/broker/ |
apache_, cp_ |
kcat librdkafka-2.next_ |
The idempotent-producer sequence check is Kafka 4.3.1’s: a producer with no state may start at any sequence. Kafka trunk’s KAFKA-15591 rule, which answers OUT_unstable.. |
| KIP-101 | Implemented | Leader-epoch based truncation for followers | broker/ |
broker/broker/broker/ |
in process | none | |
| KIP-107 | Implemented | DeleteRecords admin request | broker/ |
broker/broker/ |
in process | none | |
| KIP-108 | Implemented | A create-topic policy refusing a topic with POLICY_ |
broker/ |
broker/broker/broker/ |
in process | none | The policy is the declared [topic_ rule set rather than a Java class named by create.: a replication-factor floor, a partition ceiling, a min. floor, and required / forbidden config values. It runs where Kafka calls Create — after config validation, before the records are generated — on validate-only requests too. A frozen topic answers with the same error 44. |
| KIP-110 | Implemented | Zstandard compression in the v2 record batch | broker/ |
broker/broker/ |
in process | none | A zstd batch is re-compressed as snappy for a v0 or v1 fetch, because those formats never carried zstd. Those fetch versions are served only under legacy_. |
| KIP-112 | Implemented | JBOD: a broker with an offline log directory stays registered | broker/ |
broker/broker/ |
in process | none | |
| KIP-113 | Implemented | Alter |
broker/ |
broker/broker/broker/ |
cp_, cp_ |
none | |
| KIP-124 | Implemented | Request-rate quotas as a percentage of handler time | broker/ |
broker/broker/ |
in process | none | |
| KIP-133 | Implemented | An alter-config policy refusing a topic config change with POLICY_ |
broker/ |
broker/broker/broker/ |
in process | none | The same [topic_ rule set stands in for the class named by alter.. Both alter paths check the resolved post-change config map, as Alter does; its Request carries no partition count and no replication factor, so those two rules apply to Create alone. |
| KIP-207 | Implemented | The high watermark a new leader reports may regress after an election | broker/ |
broker/broker/ |
in process | none | The exhaustive data-path model checks durability without a watermark monotonicity assertion, which is what the KIP allows. ListOffsets fences a client lookup while the leader’s epoch start is above its high watermark, as Partition. |
| KIP-211 | Implemented | Committed-offset retention measured from the group’s last activity | broker/ |
broker/ |
in process | none | |
| KIP-219 | Implemented | Respond first, then mute the channel for the throttle time | broker/ |
broker/broker/ |
in process | none | Every API a request quota can hold on the ordinary dispatch path reports the delay it was held for: the dispatch loop patches a leading Throttle, and Produce, Fetch and Api – whose schemas bury the field behind an array – charge the quota in the handler and set it on the typed response instead. The dispatch loop decodes and encodes again the other buried-field responses (the delegation-token APIs and Offset) to set the field. The throttle-echo section below lists the buried-field APIs and what each one’s Request costs. |
| KIP-226 | Implemented | DescribeConfigs reports the source of every value | broker/ |
broker/ |
apache_, cp_, cp_ |
none | A broker resource is checked against Kafka 4.3.1’s whole Kafka key roster: a key that is not dynamic is refused, and every dynamic key is parsed and range-checked. Dynamic keys with no krabka behaviour behind them (thread pool sizes, the log cleaner, connection limits, SSL and SASL listener settings, listeners) are stored and reported and do not change how the broker runs, and a CLASS value is accepted without loading the class. |
| KIP-227 | Implemented | Incremental fetch sessions | broker/ |
broker/ |
in process | none | |
| KIP-255 | Implemented | SASL/ |
broker/ |
broker/ |
in process | none | |
| KIP-257 | Implemented | Quota entities keyed by user, client id, or both | broker/ |
broker/broker/ |
in process | none | |
| KIP-279 | Implemented | Leader-epoch truncation that converges after several leader changes | log/ |
log/broker/ |
in process | none | |
| KIP-290 | Implemented | Prefixed ACL patterns and the MATCH filter | broker/ |
broker/ |
in process | none | |
| KIP-320 | Implemented | Leader epochs in Fetch and ListOffsets, and Offset |
broker/ |
broker/broker/broker/ |
apache_, apache_, cp_, cp_ |
none | |
| KIP-345 | Implemented | Static consumer-group membership | broker/ |
broker/broker/ |
apache_, cp_, cp_ |
none | |
| KIP-360 | Implemented | Epoch bump when a transactional producer re-initialises | broker/ |
broker/broker/ |
apache_, cp_, cp_ |
none | |
| KIP-368 | Implemented | SASL re-authentication and session expiry | broker/ |
broker/broker/broker/broker/ |
apache_, cp_, cp_ |
none | connections. bounds every mechanism, and PLAIN, SCRAM and GSSAPI all re-authenticate in band under it. GSSAPI carries no automated re-auth case, because the suite has no KDC. |
| KIP-371 | Implemented | ssl. maps an mTLS Subject DN to a principal |
broker/ |
broker/broker/broker/ |
cp_, cp_ |
none | The rules are per listener, under [listeners.. Kafka’s broker-wide ssl. and its listener. prefixed form are not read from server_. As in Kafka, the rules map the Subject DN on SSL listeners only, and patterns and replacements follow java.; a SASL_SSL listener takes its principal from the SASL exchange. The patterns are read as java. reads them through a rewrite for fancy_: (?i) folds ASCII case only, (?iu) folds by Character. of Character., in a character class as well, and the POSIX classes such as Alpha and Punct are ASCII unless (?U) is on. One residue remains, documented in the java_ module: a backreference under a case flag compares as fancy_ does. Under (?i) it matches a non-ASCII letter in the other case, where Java’s does not, and under (?iu) it does not match i with İ or ı, or a letter with a case that takes another number of bytes, such as s with ſ, where Java’s does. |
| KIP-373 | Implemented | Delegation tokens for other users: the USER resource type and the CREATE_ and DESCRIBE_ operations |
broker/ |
broker/broker/broker/ |
in process | none | |
| KIP-382 | Implemented | MirrorMaker 2 replicates a Kafka cluster onto krabka | broker/ |
broker/ |
apache_ |
none | The stock connect-mirror-maker. of apache/ mirrors a broker of that release onto krabka: records with their headers, MM2’s compacted heartbeats, checkpoints and offset-syncs topics, a consumer group’s translated position, and a retention. carried over by sync.. sync. is left at its default; because neither cluster in the suite has an authorizer, MM2 skips the sync at the source, and the target-side Create krabka would answer SECURITY_ is asserted directly. docs/ is the cutover procedure. Kafka trunk’s four newest topic keys (remote., remote., max., errors.) are unknown topic configs by default, as they are on 4.3.1, so a replay from a trunk cluster that sets one fails as it does against a 4.3.1 broker; unstable. accepts and describes them. With the flag on, remote. and remote. hold a sealed segment back from the remote tier (KIP-1241), and max. refuses a compressed record above it wherever the broker decompresses one, as trunk does: on produce with INVALID_; in log compaction, where it fails the pass and leaves the partition uncleanable until the limit changes, where trunk holds it until a broker restart; and in a by-timestamp or MAX_ List on the local log or the remote tier, which answers INVALID_ for a record it has to read. Follower replication is not checked, as in trunk. errors., errors. and the three *. group keys are accepted on a group with trunk’s validation and stored, and nothing reads them yet. |
| KIP-392 | Implemented | Fetch from the closest replica | broker/ |
broker/ |
in process | none | |
| KIP-394 | Implemented | JoinGroup member-id bootstrap with MEMBER_ |
broker/ |
broker/ |
in process | none | |
| KIP-405 | Implemented | Tiered storage: remote segment copy, read, retention and metadata | broker/ |
broker/broker/remote-storage/remote-storage/restore/restore/ |
cp_, cp_, apache_ |
none | The tier’s traffic and lag are published per topic under the krabka_ names, which stand for Kafka’s Broker Remote, Remote, the three Remote*Requests and Remote*Errors meters, and the four Remote*Lag* gauges. The bounded reader pool and the on-disk index cache report krabka_, _ and _ for Kafka’s Remote gauges, plus rejection and cache hit / miss counters Kafka has no counterpart for. The GCS lane of the evidence, gcs_, covers the native [remote_ backend’s reads, deletes and WORM startup gate against an emulator; it does not cover a GCS copy, because object_ writes an object with the Cloud Storage XML API and no GCS emulator serves that PUT. The copy path is covered against MinIO and In instead. |
| KIP-412 | Implemented | Dynamic broker log levels through the BROKER_LOGGER resource | broker/ |
broker/broker/ |
apache_ |
none | |
| KIP-429 | Implemented | Cooperative rebalance protocol negotiation in JoinGroup | broker/ |
broker/broker/ |
apache_, cp_, cp_ |
none | |
| KIP-430 | Implemented | Authorized-operations bitfields in Metadata, DescribeGroups and DescribeCluster | broker/ |
broker/ |
in process | none | |
| KIP-447 | Implemented | OffsetFetch require_stable and the UNSTABLE_ |
broker/ |
broker/broker/ |
in process | none | |
| KIP-455 | Implemented | Alter |
broker/ |
broker/broker/broker/ |
apache_, cp_ |
none | |
| KIP-460 | Implemented | ElectLeaders with unclean election, and automatic preferred-leader rebalance | broker/ |
broker/broker/ |
in process | none | |
| KIP-464 | Implemented | CreateTopics num_partitions and replication_ |
broker/ |
broker/ |
in process | none | |
| KIP-467 | Implemented | Per-record error indices and messages in the Produce response | broker/ |
broker/ |
in process | none | |
| KIP-482 | Implemented | Flexible versions and tagged fields, with the v2 request header | broker/ |
broker/broker/ |
in process | kcat 1.7.1 (librdkafka 1.8.2): round_kcat librdkafka-2. round_ |
|
| KIP-496 | Implemented | OffsetDelete for consumer groups | broker/ |
broker/broker/ |
apache_, cp_, cp_ |
none | |
| KIP-500 | Implemented | KRaft mode: broker heartbeats, fencing and controlled shutdown | broker/ |
broker/broker/ |
in process | none | |
| KIP-511 | Implemented | Client software name and version in ApiVersions v3 | raft/ |
broker/broker/ |
in process | kcat 1.7.1 (librdkafka 1.8.2): round_kcat librdkafka-2. round_ |
|
| KIP-516 | Implemented | Topic identifiers in Metadata, Produce, Fetch, offsets and DeleteTopics | broker/ |
broker/broker/broker/broker/broker/broker/ |
in process | kcat librdkafka-2.next_ |
|
| KIP-525 | Implemented | CreateTopics v5 returns the created topic’s configuration | broker/ |
broker/ |
in process | none | |
| KIP-534 | Implemented | Compaction retains the last tombstone and transaction marker for a delay | log/ |
log/log/broker/ |
in process | none | |
| KIP-546 | Implemented | Describe |
broker/ |
broker/broker/ |
cp_, cp_ |
none | |
| KIP-554 | Implemented | SCRAM credentials through Alter |
broker/ |
broker/broker/broker/ |
apache_, cp_, cp_ |
none | |
| KIP-559 | Implemented | protocol_type and protocol_name in JoinGroup v7 and SyncGroup v5 | broker/ |
broker/ |
in process | none | |
| KIP-584 | Implemented | Feature versioning: UpdateFeatures and the finalized features in ApiVersions | broker/ |
broker/broker/broker/ |
apache_ |
none | The finalizable features are metadata., group., transaction., share., streams., eligible. and kraft., the last finalized by a KRaft control record rather than by Update. metadata. is supported up to 4.3.1’s latest production level, 4. (30), unless Kafka’s unstable. is set, which raises it to trunk’s 4. (34), Kafka’s latest, in Api, node registration, Update and krabka format alike. |
| KIP-590 | Implemented | Envelope: the controller listener serves a forwarded admin write | broker/ |
broker/broker/ |
apache_ |
none | Metadata-dependent admin operations are forwarded in an Envelope carrying the client identity and planned on the active Krabka controller. JVM controller interoperation remains outside the compatibility target (crates/). |
| KIP-595 | Implemented | The KRaft controller quorum: Vote, Begin |
kraft-core/ |
raft/raft/broker/broker/ |
apache_ |
none | |
| KIP-599 | Implemented | Controller mutation quotas on CreateTopics, Create |
broker/ |
broker/ |
in process | none | |
| KIP-612 | Implemented | Per-IP connection creation rate quotas | broker/ |
broker/ |
in process | none | |
| KIP-630 | Implemented | Metadata snapshots: the checkpoint file and FetchSnapshot | raft/ |
raft/raft/broker/ |
apache_ |
none | |
| KIP-631 | Implemented | The KRaft metadata records and broker registration | broker/ |
raft/broker/ |
apache_ |
none | |
| KIP-642 | Out of scope | Multi-node quorum reassignment in one operation | raft/ |
none | in process | none | Voter changes go one node at a time through KIP-853. change_ rejects a batch that adds or removes more than one voter. |
| KIP-664 | Implemented | Describe |
broker/ |
broker/broker/ |
in process | none | |
| KIP-704 | Implemented | Alter |
broker/ |
broker/broker/broker/broker/ |
in process | none | Unclean election commits RECOVERING with the leader change. The controller fences illegal RECOVERED-to-RECOVERING transitions and multi-member ISR proposals that still report RECOVERING; the elected leader’s next maintenance proposal reports RECOVERED. Recovery state is stored in standard KRaft partition metadata and survives replay and snapshot restore. |
| KIP-714 | Implemented | Client metrics push: Get |
broker/ |
broker/broker/broker/ |
in process | kcat librdkafka-2.next_ |
Get[runtime] key client_, or a configured client_, which implies it. The default is off, which is what a stock Kafka broker advertises when metric. holds no Client implementation, so a modern Java or librdkafka client opens no telemetry handshake it has nowhere to push to. api_ names the gate and Broker reads it. Both handlers stay registered either way and answer a client that sends one anyway. A closed connection drops the instance it created, and an idle instance expires after the larger of one minute and three push intervals, as in Kafka. Push follows Kafka 4.3.1 in two places where trunk has since changed: every push sets the instance’s terminating flag, a rejected one included, and a payload that decompresses past telemetry. is answered INVALID_. unstable. selects trunk’s behavior for both, which records the flag only for an accepted push (KAFKA-20898) and answers TELEMETRY_ (KAFKA-21076). The match patterns of a subscription are java. patterns, read through the same rewrite, and the same residue remains, documented in the java_ module: a backreference under a case flag compares as fancy_ does. Under (?i) it matches a non-ASCII letter in the other case, where Java’s does not, and under (?iu) it does not match i with İ or ı, or a letter with a case that takes another number of bytes, such as s with ſ, where Java’s does. |
| KIP-734 | Implemented | ListOffsets MAX_TIMESTAMP | broker/ |
broker/ |
in process | none | |
| KIP-768 | Implemented | SASL/ |
broker/ |
broker/broker/broker/verified/ |
in process | none | The broker half of the KIP: crates/ GETs the provider’s JWKS document over HTTP or HTTPS, parses it, and swaps the key set into the shared Jwks a Signed reads, so rotated keys are picked up with no restart. It refreshes on a cadence and on a validator’s unknown-kid signal, rate-limits the on-demand path, keeps the previous key set when a fetch fails, and fences readers with the even/odd generation counter that crates/ proves admission against; the same file’s crates/ keeps the on-demand limiter monotonic across a wall-clock rollback. Cache expiry, issuer and audience checks, the principal and groups claims, the typ check, clock skew, an operator-supplied Id TLS trust bundle and the use=enc filter are configured from the [oauthbearer] TOML table rather than Kafka’s sasl. JAAS options. The KIP’s client half – the login callback that retrieves a token with an OAuth client_ grant – is a client concern and lives in krabka-client-rs, not in this repository. |
| KIP-778 | Implemented | metadata.krabka format bootstraps |
format/ |
format/broker/ |
in process | none | |
| KIP-814 | Implemented | A static leader that rejoins a stable group gets skip_ and keeps the current assignment |
broker/ |
broker/ |
in process | none | |
| KIP-827 | Implemented | DescribeLogDirs v4 reports total and usable bytes per directory | broker/ |
broker/ |
cp_, cp_ |
none | |
| KIP-835 | Implemented | The KRaft leader appends a NoOpRecord every metadata. |
raft/ |
raft/raft/raft/broker/broker/ |
in process | none | The NoOpRecord heartbeat is in the tree. Controller and broker metrics publish the last applied record offset and append timestamp, and time since that timestamp. Pending-record processing gauges report the process-lifetime average and maximum microseconds spent on completed apply passes that advanced across pending committed records. Gauges refresh on the broker polling interval. |
| KIP-841 | Implemented | Unclean leader election when the ISR is empty and the topic allows it | broker/ |
broker/broker/ |
in process | none | |
| KIP-848 | Implemented | The next-generation consumer group protocol | broker/ |
broker/broker/broker/broker/broker/ |
apache_, cp_, apache_, cp_, cp_ |
kcat librdkafka-2.next_ |
A Consumer whose Subscribed does not compile is answered INVALID_ (128) before any member record is written, and the member is not admitted, as Kafka does. The pattern is compiled with Rust regex in Unicode mode, which accepts RE2J’s Unicode character classes; topic names are ASCII, so RE2J’s ASCII-only perl classes cannot diverge on a match. An inline flag group naming a flag RE2J has no equivalent for (x, u, R) is rejected ahead of the compile with RE2J’s own message, since regex would take it. The re2j wrapper translates RE2J’s \\Q. literal quoting and character-class rules before compiling, while keeping Rust regex’s bounded non-backtracking matching. A repetition large enough to exceed regex’s compiled-size limit remains a narrow acceptance difference. No JVM-lane case covers the refusal: Kafka and kafka-console-consumer --include compile the pattern locally with java., so a stock JVM client never sends an invalid one to the broker. The group resolves each subscribed regex once for all its members, as Kafka’s Topic does: against the metadata image, keeping the topics that the principal of the heartbeat that resolves it may Describe. It records the result as a Consumer record, so a coordinator failover restores the topics of every regex subscription without a heartbeat that carries the pattern. A heartbeat of any member resolves the patterns again when a member’s pattern is not resolved yet, when a topic was created since the last resolution, or when the last one is older than group. (10 minutes), and never within 10 seconds of the last one. A change of the ACLs counts as a new topic here, where Kafka picks it up at the refresh interval. A group’s consumer., consumer. and consumer. are accepted, validated against the group. and group. bounds and stored by Alter and Incremental on a GROUP resource, as Kafka does, and the consumer coordinator applies them to that group over the broker’s group. values. A next target assignment waits for consumer. (1 s by default) since the last one, as in Kafka’s can. |
| KIP-853 | Implemented | Dynamic controller quorum: AddRaftVoter, Remove |
raft/ |
broker/raft/broker/ |
apache_ |
none | |
| KIP-858 | Implemented | Directory identifiers: Assign |
broker/ |
broker/broker/ |
in process | none | |
| KIP-860 | Implemented | Alter |
broker/ |
broker/ |
in process | none | |
| KIP-890 | Implemented | Transactions v2: verify-only Add |
broker/ |
broker/broker/ |
in process | none | What a request may do follows its API version, as in Kafka, whatever transaction. the cluster finalized: EndTxn v5 and Add_ value format and the rules of a server-initiated abort. Two answers follow Kafka trunk only under unstable.: an EndTxn v5 commit at the pre-abort epoch after CompleteAbort answers PRODUCER_FENCED (KAFKA-20785, where 4.3.1 answers INVALID_Last (tag 4) is written to and read from _ (KAFKA-20357, where 4.3.1 keeps it in memory). A transactional offset commit records the topic id only from TxnOffsetCommit v6 and under that flag. |
| KIP-903 | Implemented | Broker epochs fence stale replicas in AlterPartition | broker/ |
raft/broker/ |
in process | none | |
| KIP-919 | Implemented | Admin clients bootstrap from controllers: Controller |
broker/ |
broker/broker/broker/ |
apache_ |
none | |
| KIP-932 | Implemented | Share groups: membership, ShareFetch, Share |
broker/ |
broker/broker/broker/broker/ |
apache_ |
none | Group-level configs are accepted, validated and stored for every key of Kafka 4.3.1’s Group, by Alter and Incremental on a GROUP resource, as Kafka does. The share partitions apply share., share., share., share., share. and share.. The share coordinator applies share., share. and share. to that group over the broker’s group. values, and a next target assignment waits for the assignment interval (1 s by default) since the last one, as in Kafka’s can. |
| KIP-939 | Implemented | Two-phase commit transactions with the KIP-939 timeout rules | broker/ |
broker/broker/ |
in process | none | Init v6 is latest in Kafka 4.3.1, so it is served only under unstable., and 2PC itself only under transaction.. keep is answered UNSUPPORTED_Transaction answers it, unless both switches are on; then krabka’s prepared-transaction recovery serves it, which no Kafka release implements. |
| KIP-950 | Implemented | Tiered storage disablement: remote. |
broker/ |
broker/broker/ |
cp_, cp_ |
none | remote. going true -> false is refused unless remote. comes with it, and the flip then erases the partition’s remote segments and raises its log start offset to the local log start. remote. is the read-only tier: no new copies, reads and remote retention unchanged. Under a WORM archive the cascade clears the partition’s remote metadata and removes nothing from the archive, as a Delete cascade does. |
| KIP-951 | Implemented | Leader hints in the Produce and Fetch responses | broker/ |
broker/broker/ |
in process | none | |
| KIP-966 | Implemented | Eligible leader replicas, unclean recovery and Describe |
broker/ |
broker/broker/broker/broker/ |
apache_, cp_, cp_ |
none | ELR maintenance is gated on the eligible. feature, as Kafka gates it on Feature: at level 0 the controller publishes no eligible or last-known-eligible set, and a downgrade to 0 clears what an earlier level 1 published. The release default is level 1 from metadata. 4.1-IV0, where ELRV_ bootstraps, and 0 below it; level 1 declares Kafka’s KIP-1022 dependency on metadata. at 4.0-IV1. ELR is carried by standard per-partition KRaft metadata and is consumed during JVM-compatible replay. The last-known ELR follows Kafka 4.3.1’s Partition (use is always on): it holds the single last leader of a partition that has no leader and is empty otherwise, and when that leader returns it is elected as an unclean leader (RECOVERING, a singleton ISR) with no unclean. or unclean. consulted, unless an ELR member is there to lead cleanly first. krabka’s partition record always names a leader, so a partition with no leader keeps its last leader in the record, marks it with that one-member last-known ELR, and Metadata and Describe report it as leader = -1; the election runs when a broker unfences (handle). The operator election in Elect does not take the last-known rung. |
| KIP-996 | Implemented | Pre-vote before a KRaft election | kraft-core/ |
kraft-core/raft/broker/ |
apache_ |
none | |
| KIP-1005 | Implemented | ListOffsets LATEST_ |
broker/ |
broker/ |
in process | none | |
| KIP-1022 | Implemented | Feature flags with dependency checks at format and upgrade time | format/ |
broker/broker/ |
apache_ |
none | |
| KIP-1023 | Implemented | ListOffsets EARLIEST_ |
broker/ |
broker/ |
in process | none | |
| KIP-1038 | Implemented | List |
broker/ |
broker/broker/ |
in process | none | |
| KIP-1066 | Implemented | cordoned. |
broker/ |
broker/broker/broker/broker/broker/ |
in process | none | Matches Kafka 4.3.1. A manual CreateTopics or Createapache/ accepts it: the INVALID_ refusal The manual partition assignment includes broker N, but all its log directories are cordoned. is KAFKA-20832, which is on Kafka trunk and the 4.3 branch after 4.3.1 only. The controller does not tell a forwarded write of cordoned. from a direct one, so it does not apply Kafka’s rule that a direct controller write may only remove entries. |
| KIP-1071 | Implemented | Streams groups: Streams |
broker/ |
broker/broker/broker/broker/ |
apache_, apache_, cp_ |
none | A group’s streams. overrides, streams. and streams. included, apply per group, and a key of another coordinator stored beside them leaves them intact. |
| KIP-1073 | Implemented | DescribeCluster hides fenced brokers from clients | broker/ |
broker/ |
in process | none | |
| KIP-1075 | Implemented | A server-side timeout for remote ListOffsets work | broker/ |
broker/ |
in process | none | |
| KIP-1101 | Out of scope | The MetadataHash tagged field on the group-metadata records, and the streams partition-metadata record it retires | broker/ |
none | in process | none | The hash is how Kafka decides a group must rebalance because its subscribed topics changed shape. The consumer and share groups of krabka decide that from the metadata image instead and write the hash as 0, which is what Kafka writes for a group whose hash is unset, and Kafka’s own reader accepts it. The streams group keeps Kafka’s hash, because KIP-1071 configures the topology again when it changes, and writes it in its group metadata record. krabka keeps the streams partition-metadata snapshot this KIP retired, on the key version Kafka no longer assigns, where Kafka’s serde skips it as an unknown type rather than mis-reading it. |
| KIP-1142 | Implemented | List |
broker/ |
broker/ |
in process | none | |
| KIP-1155 | Implemented | A checkpoint at every metadata. |
raft/ |
raft/ |
in process | none | |
| KIP-1186 | Implemented | kraft.version upgrade and the last-voter check that the Kafka 4.3 quorum tools drive | raft/ |
broker/ |
apache_ |
none | |
| KIP-1191 | Partial | Share-group dead-letter queue: a record that a member rejects, or that uses up the delivery count limit, is written to the group’s dead-letter topic before it is archived | broker/ |
broker/broker/format/broker/broker/broker/broker/broker/broker/broker/broker/ |
in process | none | Kafka trunk’s share. 2, which a node supports only under unstable.; the topic key errors. and the group keys errors. and errors. need unstable. too, so trunk mode is both switches. At share. 1, the level a default node runs, a group’s dead-letter keys change nothing and a reject archives at once. A group with a topic name gets one record for each offset that is rejected or reaches share., with Kafka’s six _ headers and, with errors., the source key and value. It is an acks=all produce to the leader of the topic partition that the source partition maps to, as Kafka’s Share sends it, over the inter-broker listener, and it retries five times from 1 s to 30 s. The writes of a broker share one connection to each destination leader, neighbouring runs with the same delivery count and cause are one write, and at most eight writes run at once. As in Kafka’s Share, the rounds of every write that waits for one destination leader go out in as few produce requests as max. allows, across runs and partitions: one request is in flight to a leader, the rounds that arrive meanwhile go out together in the next, the rounds for one partition are one batch, and each write archives its run when the response holds the row for its own partition, and retries on its own. The eight writers are the most runs that share a request. The record is persisted as delivery state ARCHIVING (3) first and as ARCHIVED (4) when the write ends, whatever its result, and a leader that finds ARCHIVING after a restart writes the record again, as Share and maybe do. The topic has to have errors., a name that starts with errors. (default dlq.) and not with _, and a missing topic is created only when errors. is true. Both cluster keys are read from the dynamic broker config, per broker and then cluster-wide, and neither is in the Describe key roster of a broker yet. The Dead meters of Kafka’s Share are exported for each group as the counters krabka_ (Dead), krabka_ (Dead, one for each round of each write for each attempt, as Kafka counts it) and krabka_ (Dead), and group., a JVM class name, has no counterpart. A copied record that the six headers and the batch header push over max. is written with its headers alone, where trunk’s writer sends it whole and loses it to MESSAGE_. |
| KIP-1222 | Implemented | Share acquisition lock renewal: the Renew acknowledge type and IsRenewAck on ShareFetch and Share |
broker/ |
broker/broker/broker/ |
in process | none | share. (default true) is a Group key that Alter and Incremental accept on a GROUP resource and that the share partitions apply: a group that sets it to false answers a Renew acknowledgement with INVALID_ |
| KIP-1241 | Implemented | Delayed remote copy: remote. |
broker/ |
broker/broker/broker/ |
in process | none | Kafka trunk’s topic keys and their log. and log. broker defaults, served only under unstable.. By default they are unknown configs, as on 4.3.1, and a sealed segment is copied as soon as it is sealed. With the flag on, the copy pass stops at the first sealed segment that is neither old enough by its newest record nor far enough behind newer local data, as RLMCopy does. |
| KIP-1242 | Implemented | ApiVersions v5 routing identity and REBOOTSTRAP_ |
broker/ |
broker/ |
in process | none | Kafka trunk’s ApiVersions v5, served only under unstable.. By default both listeners serve 4.3.1’s v0-v4 and answer v5 UNSUPPORTED_ with that range, so REBOOTSTRAP_Sasl answers it: INVALID_ for an invalid request and otherwise the table, with no routing check. |
| KIP-1251 | Implemented | OffsetCommit accepts an older member epoch for a partition assigned at or before that epoch | broker/ |
broker/broker/ |
in process | none | |
| KIP-1263 | Out of scope | The Assignment |
broker/ |
none | in process | none | Kafka stamps each target assignment with the time it was computed, for its own assignment metrics. krabka does not measure assignment latency from the log, so it writes the tagged field’s default of 0, which is what Kafka writes when it has no timestamp to record. |
| KIP-1276 | Implemented | CIDR-range ACL hosts (10.0.0.0/8, 2001:db8::/32) in CreateAcls and host matching | authz/ |
authz/authz/broker/ |
in process | none | Trunk behavior, behind unstable.. By default Create and the authorizer behave as Kafka 4.3.1 does: any host, an empty one or one containing / included, is stored and compared as text. Under the flag Create applies trunk’s validate, which accepts a CIDR host from metadata. 4.4-IV1 (level 32) and answers UNSUPPORTED_/ as a range from that version. |
| KIP-1312 | Implemented | Unregister |
broker/ |
broker/broker/broker/broker/ |
in process | none | Matches Kafka trunk: no Kafka release has api key 94. The controller listener answers it and a broker listener forwards it in an Envelope, as trunk’s Controller and Kafka do. It is advertised and accepted only under unstable.; by default a request for key 94 closes the connection, as it does against a 4.3.1 broker or controller, and an Envelope carrying one is answered UNSUPPORTED_metadata. 4.4-IV2 (level 33), which a node supports only under unstable., and answers trunk’s UNSUPPORTED_ |
| KIP-1319 | Implemented | TxnOffsetCommit v6: topics by id, GROUP_ |
broker/ |
broker/broker/broker/ |
in process | none | Kafka trunk’s TxnOffsetCommit v6, which Kafka 4.3.1 predates, served only under unstable.. By default the broker advertises and accepts 4.3.1’s v0-v5. |
| KIP-1331 | Partial | Streams topology descriptions: Streams |
broker/ |
broker/broker/broker/broker/broker/broker/broker/broker/broker/broker/ |
in process | none | Matches Kafka trunk, and served only under unstable.: by default Streamsstreams. group keys are unknown group configs. Without group., as a Kafka broker runs by default, a heartbeat never sets TopologyThe broker has no streams group topology description plugin configured. once the streams protocol and group Read gates pass. krabka cannot load a JVM class, so the key accepts only Kafka’s reference plugin, org., which krabka builds in, and any other class stops the broker at startup. With that plugin, a version 1 heartbeat asks one member for the description under Kafka’s back-off of 30 seconds that doubles to one hour. The broker keeps the pushed description in memory and its epoch in the Stored of the group metadata record, a describe answers it as AVAILABLE, and DeleteGroups drops it. As with Kafka’s in-memory plugin, a broker restart or a coordinator move loses the description but keeps the stored epoch, so the group is not asked again until its topology epoch changes. Kafka writes the UNCERTAIN epoch before it calls the plugin, and krabka, whose plugin stores in the same step, writes only the pushed epoch. The built-in plugin never fails, so Failed stays -1 and there is no cleanup cycle for a plugin to retry. Heartbeat v1 carries MISSING_streams., whose default is the broker’s group., is missing from the member’s client tags. DeleteGroups v3, which adds a per-group ErrorMessage, is trunk’s too and is advertised only under the same flag. krabka never answers GROUP_ |
| KIP-1357 | Implemented | Streams |
broker/ |
broker/ |
in process | none | Kafka trunk’s Streamsunstable.. |
| SASL/GSSAPI | Implemented | SASL/Kerberos authentication | broker/ |
broker/broker/ |
in process | none | Kerberos predates the KIP process (KAFKA-1686, Kafka 0.9), so no KIP number. Both suites run in the scheduled container gssapi CI job: the KDC fixture writes keytabs through a bind mount, so the lane is schedule and workflow_ |
| mixed-quorum | Out of scope | A controller quorum with both JVM and Krabka voters | raft/ |
none | in process | none | Outside the raft crate’s compatibility target: crates/. |
Kafka images
| Key | Image |
|---|---|
apache_ |
mirror. |
apache_ |
mirror. |
apache_ |
mirror. |
cp_ |
mirror. |
cp_ |
mirror. |
cp_ |
mirror. |
cp_ |
mirror. |
On-disk log contract
The suite covers timestamped record batches (KIP-32), segment and index
discovery, and record key/value recovery in both directions. It ran against
mirror.gcr.io/confluentinc/cp-kafka:6.1.1@sha256:537c303f182ff6ba665f324520105c44970c97d7ef94b306709a5d68b8c1aed7.
| Direction | Status | Contract | Owner | Differential test | Kafka image |
|---|---|---|---|---|---|
| JVM -> krabka | Implemented | Open and read a JVM-written Kafka log directory | crates/ |
read_ |
mirror. |
| krabka -> JVM | Implemented | Restart Kafka over a krabka-written log directory and consume it | crates/ |
jvm_ |
mirror. |
Advertised API versions
kafka-broker-api-versions read both tables below.
api_versions_differential
asserts krabka’s against
api_catalog and records the join in
divergence.json,
which is where these two version columns come from. A range that moves, or a key
that appears on one side only, changes that file and so changes this table.
The oracle is mirror.gcr.io/apache/kafka:4.3.1@sha256:ccd1314e47ec76909e01f86308b4dcf2064f19f7c89759234322314b0e319e26.
It is a stock single-node KRaft broker, read on its PLAINTEXT broker listener.
krabka is read the same way: one client listener, no client-telemetry receiver,
and both version switches at their defaults. unstable.api.versions.enable is
Kafka’s own; legacy_request_versions_enable is krabka’s. With those defaults
krabka advertises exactly Kafka 4.3.1’s table, so every row below should match.
A krabka only or Kafka only verdict would mean the two brokers disagree on
which keys exist.
What krabka serves past 4.3.1 is opt-in, and so it does not appear here. Kafka
trunk’s ApiVersions v5, TxnOffsetCommit v6, the streams v1 pair, and api
keys 93 and 94 need unstable.api.versions.enable. The pre-4.0 Fetch,
ListOffsets and Produce versions need legacy_request_versions_enable. The
KIP rows above name each one.
A row whose ranges differ carries the reason krabka means to differ, recorded
beside the ranges themselves in RANGE_DIVERGENCE_INTENTS
(divergence.rs).
The suite panics on a range divergence with no entry there, so a range that
moves cannot reach this page unexplained. Every other verdict leaves the column
empty.
| API | Key | krabka | Kafka | Verdict | Intent |
|---|---|---|---|---|---|
| Produce | 0 | 0-13 | 0-13 | match | – |
| Fetch | 1 | 4-18 | 4-18 | match | – |
| ListOffsets | 2 | 1-11 | 1-11 | match | – |
| Metadata | 3 | 0-13 | 0-13 | match | – |
| OffsetCommit | 8 | 2-10 | 2-10 | match | – |
| OffsetFetch | 9 | 1-10 | 1-10 | match | – |
| FindCoordinator | 10 | 0-6 | 0-6 | match | – |
| JoinGroup | 11 | 0-9 | 0-9 | match | – |
| Heartbeat | 12 | 0-4 | 0-4 | match | – |
| LeaveGroup | 13 | 0-5 | 0-5 | match | – |
| SyncGroup | 14 | 0-5 | 0-5 | match | – |
| DescribeGroups | 15 | 0-6 | 0-6 | match | – |
| ListGroups | 16 | 0-5 | 0-5 | match | – |
| SaslHandshake | 17 | 0-1 | 0-1 | match | – |
| ApiVersions | 18 | 0-4 | 0-4 | match | – |
| CreateTopics | 19 | 2-7 | 2-7 | match | – |
| DeleteTopics | 20 | 1-6 | 1-6 | match | – |
| DeleteRecords | 21 | 0-2 | 0-2 | match | – |
| InitProducerId | 22 | 0-5 | 0-5 | match | – |
| Offset |
23 | 2-4 | 2-4 | match | – |
| Add |
24 | 0-5 | 0-5 | match | – |
| AddOffsetsToTxn | 25 | 0-4 | 0-4 | match | – |
| EndTxn | 26 | 0-5 | 0-5 | match | – |
| WriteTxnMarkers | 27 | 1-2 | 1-2 | match | – |
| TxnOffsetCommit | 28 | 0-5 | 0-5 | match | – |
| DescribeAcls | 29 | 1-3 | 1-3 | match | – |
| CreateAcls | 30 | 1-3 | 1-3 | match | – |
| DeleteAcls | 31 | 1-3 | 1-3 | match | – |
| DescribeConfigs | 32 | 1-4 | 1-4 | match | – |
| AlterConfigs | 33 | 0-2 | 0-2 | match | – |
| Alter |
34 | 1-2 | 1-2 | match | – |
| DescribeLogDirs | 35 | 1-5 | 1-5 | match | – |
| Sasl |
36 | 0-2 | 0-2 | match | – |
| Create |
37 | 0-3 | 0-3 | match | – |
| Create |
38 | 1-3 | 1-3 | match | – |
| Renew |
39 | 1-2 | 1-2 | match | – |
| Expire |
40 | 1-2 | 1-2 | match | – |
| Describe |
41 | 1-3 | 1-3 | match | – |
| DeleteGroups | 42 | 0-2 | 0-2 | match | – |
| ElectLeaders | 43 | 0-2 | 0-2 | match | – |
| Incremental |
44 | 0-1 | 0-1 | match | – |
| Alter |
45 | 0-1 | 0-1 | match | – |
| List |
46 | 0-0 | 0-0 | match | – |
| OffsetDelete | 47 | 0-0 | 0-0 | match | – |
| Describe |
48 | 0-1 | 0-1 | match | – |
| Alter |
49 | 0-1 | 0-1 | match | – |
| Describe |
50 | 0-0 | 0-0 | match | – |
| Alter |
51 | 0-0 | 0-0 | match | – |
| DescribeQuorum | 55 | 0-2 | 0-2 | match | – |
| UpdateFeatures | 57 | 0-2 | 0-2 | match | – |
| DescribeCluster | 60 | 0-2 | 0-2 | match | – |
| Describe |
61 | 0-0 | 0-0 | match | – |
| Unregister |
64 | 0-0 | 0-0 | match | – |
| Describe |
65 | 0-0 | 0-0 | match | – |
| List |
66 | 0-2 | 0-2 | match | – |
| Consumer |
68 | 0-1 | 0-1 | match | – |
| Consumer |
69 | 0-1 | 0-1 | match | – |
| List |
74 | 0-1 | 0-1 | match | – |
| Describe |
75 | 0-0 | 0-0 | match | – |
| Share |
76 | 1-1 | 1-1 | match | – |
| Share |
77 | 1-1 | 1-1 | match | – |
| ShareFetch | 78 | 1-2 | 1-2 | match | – |
| Share |
79 | 1-2 | 1-2 | match | – |
| AddRaftVoter | 80 | 0-1 | 0-1 | match | – |
| RemoveRaftVoter | 81 | 0-0 | 0-0 | match | – |
| Initialize |
83 | 0-0 | 0-0 | match | – |
| Read |
84 | 0-0 | 0-0 | match | – |
| Write |
85 | 0-1 | 0-1 | match | – |
| Delete |
86 | 0-0 | 0-0 | match | – |
| Read |
87 | 0-1 | 0-1 | match | – |
| Streams |
88 | 0-0 | 0-0 | match | – |
| Streams |
89 | 0-0 | 0-0 | match | – |
| Describe |
90 | 0-1 | 0-1 | match | – |
| Alter |
91 | 0-0 | 0-0 | match | – |
| Delete |
92 | 0-0 | 0-0 | match | – |
The Bazel Docker lane supplies each image from a digest-pinned OCI repository. CI regenerates this page and fails when the test names, lane, image tag, digest, recorded API versions, or checked-in output drift.
KIP-219 throttle-echo divergences
The broker reports a request-quota delay by patching the leading
ThrottleTimeMs int32 of an already-encoded response, so it can only echo the
delay on responses whose schema puts that field first. Every advertised API is
audited by
throttle_audit,
which encodes each response at each advertised version and compares where
ThrottleTimeMs lands against the broker’s table.
The APIs below carry ThrottleTimeMs behind another field, so the patch
cannot reach it. That is a statement about the schema, not about what a client
observes: whether a request-quota delay is ever applied to one of these APIs is
decided separately, by its dispatch entry’s RequestQuotaPolicy. The two
columns are kept apart for that reason.
SelfAccountedentries charge the quota in the handler and setThrottleTimeMson the typed response before encoding, so the buried field costs nothing and the client does see the delay.ApplyFallbackAccountingentries are the ones the dispatch loop charges and delays. For the buried-field APIs below, the dispatch loop decodes the response, setsThrottleTimeMsand encodes it again, so the client does see the delay.InlineExemptentries are the APIs Kafka answers throughsendResponseExemptThrottle(WriteTxnMarkers,AlterPartition,FetchSnapshot,UpdateRaftVoter) and the SASL handshake APIs, which Kafka answers in the authenticator. They are never delayed by the request quota on the ordinary path.
recorded_reach_matches_the_dispatch_registry in the audit pins the last
column against the assembled dispatch registry, so a policy change on any of
these APIs fails the build until this page is regenerated.
| API | api_key | Versions | Why the field cannot be patched | Runtime effect |
|---|---|---|---|---|
| Produce | 0 | 1-13 | Sits behind the Responses array, at an offset the response header does not fix |
None. The handler charges its own quota and sets Throttle on the typed response before encoding, so the client does see the delay |
| ApiVersions | 18 | 1-5 | Sits behind the Api array, at an offset the response header does not fix |
None. The handler charges its own quota and sets Throttle on the typed response before encoding, so the client does see the delay |
| Create |
38 | 1-3 | Last field, behind the principal strings, the token timestamps and the HMAC | None. The dispatch loop charges the quota, then decodes the response, sets Throttle and encodes it again, so the client does see the delay |
| Renew |
39 | 1-2 | Last field, behind Error and the new expiry timestamp |
None. The dispatch loop charges the quota, then decodes the response, sets Throttle and encodes it again, so the client does see the delay |
| Expire |
40 | 1-2 | Last field, behind Error and the new expiry timestamp |
None. The dispatch loop charges the quota, then decodes the response, sets Throttle and encodes it again, so the client does see the delay |
| Describe |
41 | 1-3 | Last field, behind Error and the variable-length token list |
None. The dispatch loop charges the quota, then decodes the response, sets Throttle and encodes it again, so the client does see the delay |
| OffsetDelete | 47 | 0 | Leads with Error; the field is at a fixed offset of 2, but the dispatch loop patches leading fields only |
None. The dispatch loop charges the quota, then decodes the response, sets Throttle and encodes it again, so the client does see the delay |