Skip to content

[fix][client] Avoid exception in ConsumerImpl hasMessageAvailable before first receive#25857

Open
void-ptr974 wants to merge 1 commit into
apache:masterfrom
void-ptr974:fix-25837-has-message-available
Open

[fix][client] Avoid exception in ConsumerImpl hasMessageAvailable before first receive#25857
void-ptr974 wants to merge 1 commit into
apache:masterfrom
void-ptr974:fix-25837-has-message-available

Conversation

@void-ptr974
Copy link
Copy Markdown
Contributor

@void-ptr974 void-ptr974 commented May 23, 2026

Fixes #25837

Motivation

ConsumerImpl.hasMessageAvailable() can throw UnsupportedOperationException: Unknown MessageId type: null when it is called before any message has been dequeued from a consumer created through newConsumer().subscribe().

hasMessageAvailable is not part of the Consumer public interface, but ConsumerImpl exposes it as a public implementation method. The public Reader API also delegates its hasMessageAvailable methods to the underlying consumer implementation. In the failing consumer state, startMessageId can be null, and the existing comparison path eventually calls MessageIdAdv.compareTo(null).

Modifications

  • Handle the initial startMessageId == null state by querying the broker for the last message id response and comparing it with the subscription mark-delete position.
  • Extract the mark-delete comparison logic so the existing latest/timestamp path and the null-start path share the same behavior.
  • Use FutureUtil.unwrapCompletionException(...) when propagating failures from hasMessageAvailableAsync().
  • Add regression coverage for the ConsumerImpl implementation method, the public Reader API path, and empty-topic behavior.

Verifying this change

This change added tests and can be verified as follows:

  • Added SimpleProducerConsumerTest.testConsumerImplHasMessageAvailableDoesNotThrowBeforeReceive.
  • Added SimpleProducerConsumerTest.testReaderHasMessageAvailableDoesNotThrowBeforeRead.
  • Added SimpleProducerConsumerTest.testHasMessageAvailableDoesNotThrowOnEmptyTopic.
  • Ran:
./gradlew :pulsar-broker:test --tests org.apache.pulsar.client.api.SimpleProducerConsumerTest.testConsumerImplHasMessageAvailableDoesNotThrowBeforeReceive --tests org.apache.pulsar.client.api.SimpleProducerConsumerTest.testReaderHasMessageAvailableDoesNotThrowBeforeRead --tests org.apache.pulsar.client.api.SimpleProducerConsumerTest.testHasMessageAvailableDoesNotThrowOnEmptyTopic --no-configuration-cache

Does this pull request potentially affect one of the following parts:

  • Dependencies (add or upgrade a dependency)
  • The public API
  • The schema
  • The default values of configurations
  • The threading model
  • The binary protocol
  • The REST endpoints
  • The admin CLI options
  • The metrics
  • Anything that affects deployment

@void-ptr974 void-ptr974 force-pushed the fix-25837-has-message-available branch 2 times, most recently from a3d500b to 8d5b38d Compare May 23, 2026 02:41
@void-ptr974 void-ptr974 force-pushed the fix-25837-has-message-available branch from 8d5b38d to 75370b3 Compare May 23, 2026 02:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug][Client] hasMessageAvailable() throws UnsupportedOperationException when consumer created via newConsumer().subscribe() before any message is read

1 participant