Skip to content

KAFKA-20782: IQ bug under streams protocol#22778

Open
UladzislauBlok wants to merge 2 commits into
apache:trunkfrom
UladzislauBlok:bloku/kafka-streams-iq
Open

KAFKA-20782: IQ bug under streams protocol#22778
UladzislauBlok wants to merge 2 commits into
apache:trunkfrom
UladzislauBlok:bloku/kafka-streams-iq

Conversation

@UladzislauBlok

@UladzislauBlok UladzislauBlok commented Jul 7, 2026

Copy link
Copy Markdown
Contributor

Looks like IQ is broken when:

  • New streams protocol is used
  • number of threads is more than 1

Streams result:

Gradle Test Run :streams:integration-tests:test > Gradle Test Executor 7 > IQv2EndpointToPartitionsIntegrationTest > shouldGetCorrectHostPartitionInformation(String, boolean, int, String) > STREAMS protocol No standby FAILED
    org.opentest4j.AssertionFailedError: Condition not met within timeout 60000. Kafka Streams one didn't get 4 tasks ==> expected: <true> but was: <false>

Classic result (still fail but overall number of tasks are correct, see error message):

Gradle Test Run :streams:integration-tests:test > Gradle Test Executor 11 > IQv2EndpointToPartitionsIntegrationTest > shouldGetCorrectHostPartitionInformation(String, boolean, int, String) > CLASSIC protocol No standby FAILED
    org.opentest4j.AssertionFailedError: Condition not met within timeout 15000. KafkaStreams one never released active tasks and received standby task ==> expected: <true> but was: <false>

Root cause:
partitionsByHost.put(new StreamsRebalanceData.HostInfo(userEndpoint.host(), userEndpoint.port()), endpointPartitions);

private static Map<StreamsRebalanceData.HostInfo, StreamsRebalanceData.EndpointPartitions> convertHostInfoMap(

As I understand under classic protocol entire host is considered as one member, so it's okay to override metadata view by host + port
The new protocol conciser each stream-thread as independent member (correct me if I'm wrong), so we need to union all threads metadata instead of overriding it (map#merge ??)
Now effect is that metadataForAllStreamsClients() returns only 1 / n threads metadata
(to be confirmed)

Reviewers: Alieh Saeedi asaeedi@confluent.io

@github-actions github-actions Bot added triage PRs from the community streams tests Test fixes (including flaky tests) small Small PRs labels Jul 7, 2026
@UladzislauBlok

Copy link
Copy Markdown
Contributor Author

@lucasbru @mjsax
Hey guys,
I think we have a regression in IQ with new protocol enabled. When setting number of threads is more than 1 we see only last updated thread metadata instead of merged view

@UladzislauBlok UladzislauBlok changed the title KAKFA-XXX: IQ bug under streams protocol KAKFA-20782: IQ bug under streams protocol Jul 7, 2026
@UladzislauBlok UladzislauBlok changed the title KAKFA-20782: IQ bug under streams protocol KAFKA-20782: IQ bug under streams protocol Jul 7, 2026
@aliehsaeedii

Copy link
Copy Markdown
Contributor

Thanks @UladzislauBlok for informing us. I'm checking the code...

@aliehsaeedii aliehsaeedii left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @UladzislauBlok — I checked the code and can confirm your root cause analysis.

The broker side: Since with group.protocol=streams every stream thread is an individual group member, all threads of the same instance report the same application.server endpoint — so the heartbeat response contains multiple entries with an identical host:port.

On the client side, convertHostInfoMap() then puts those entries into a HashMap keyed by host:port, so the last entry wins and the partitions of all other threads of that instance are dropped. The map flows via StreamsRebalanceData into StreamsMetadataState#onChange() (see StreamThread), which backs metadataForAllStreamsClients() / queryMetadataForKey(). So with n threads, IQ metadata reflects only one member's share of the instance's partitions — exactly what you observed.

Regarding the classic protocol: it is indeed not affected, because there the leader aggregates all tasks of a process (across all its threads) in StreamsPartitionAssignor#populatePartitionsByHostMaps() BEFORE keying by host, so no duplicate host entries ever exist. The classic failure you saw is unrelated to the metadata: the test asserts on a single thread via metadataForLocalThreads().iterator().next() and expects it to hold 2 active tasks, which cannot hold once the instance has 3 threads — those assertions would need to aggregate across threads for a multi-threaded setup.

FWIW, the bug has existed since IQ support for KIP-1071 landed on trunk (KAFKA-19135), so all releases from 4.1.0 onwards are affected. Are you interested in pushing the fix?

@UladzislauBlok

Copy link
Copy Markdown
Contributor Author

@aliehsaeedii
Would love to. While fix doesn't seem to be too complicated (not too confident about that, I will need to dig deeper), I'm curious if we need to prepare patch releases: 4.2.2 and 4.3.2 (and ofc merge to trunk and include in 4.4.0)?

@github-actions github-actions Bot added consumer clients and removed triage PRs from the community labels Jul 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clients consumer small Small PRs streams tests Test fixes (including flaky tests)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants