Skip to content

[fix][broker] Derive scalable topic identity from the raw local name - #26668

Merged
nodece merged 1 commit into
apache:masterfrom
TimurRakhmatullin86:fix/to-scalable-topic-local-name
Sep 21, 2026
Merged

nodece merged 1 commit into
apache:masterfrom
TimurRakhmatullin86:fix/to-scalable-topic-local-name

Conversation

@TimurRakhmatullin86

Copy link
Copy Markdown
Contributor

Motivation

TopicName.toScalableTopic() builds the topic:// identity from base.getEncodedLocalName(), which URL-encodes the local name via Codec.encode. But TopicName parsing never URL-decodes local names — the constructor stores the name verbatim. So for any local name containing a character URLEncoder rewrites (a space, +, %, a non-ASCII character…), the derived scalable identity is a different topic than the same topic addressed directly in the topic:// domain, and it can collide with a topic literally named after the encoded form.

For example:

  • TopicName.get("persistent://t/ns/a b").toScalableTopic() yields topic://t/ns/a+b (local name a+b), not topic://t/ns/a b — two identities for one topic, and a collision with a topic literally named a+b.
  • A % is double-encoded on the next round trip: x%20y becomes x%2520y.

Everywhere else getEncodedLocalName() is used only when serializing to a REST or metadata path; identities are otherwise spliced from the raw local name.

Modifications

Splice the raw local name (base.getLocalName()) instead of the encoded one, so the derived scalable topic round-trips through TopicName parsing and matches the same topic addressed directly. Added a short Javadoc note on why encoding must not be applied here.

Added TopicNameTest#testToScalableTopicPreservesLocalName, which asserts that the local name is preserved, both spellings resolve to the same identity, there is no collision with a literally-+ name, a % is not re-encoded, and partition stripping keeps the verbatim name.

Verifying this change

This change is covered by the added unit test TopicNameTest#testToScalableTopicPreservesLocalName. It fails without the fix (expected [a b] but found [a+b]) and passes with it. No existing test changes behavior, because existing tests use plain names for which Codec.encode is the identity.

Found by code inspection; there is no pre-existing issue.

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

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

Documentation

  • doc-not-needed

@TimurRakhmatullin86
TimurRakhmatullin86 force-pushed the fix/to-scalable-topic-local-name branch from 768c9be to b1c4266 Compare September 21, 2026 04:02
@TimurRakhmatullin86 TimurRakhmatullin86 changed the title [fix][common] Derive scalable topic identity from the raw local name [fix] Derive scalable topic identity from the raw local name Sep 21, 2026
TopicName#toScalableTopic() built the topic:// identity from the
URL-encoded local name, but topic name parsing never URL-decodes. For
any local name containing a character that Codec.encode rewrites
(space, '+', '%', non-ASCII, ...), the derived identity differed from
the same topic spelled directly in the topic:// domain:

- persistent://t/ns/a b resolved to topic://t/ns/a+b, colliding with a
  topic literally named "a+b" and diverging from topic://t/ns/a b.
- Consumers of the result encode again when building metadata paths
  (ScalableTopicResources#topicPath), so lookups went to .../a%2Bb while
  the record created for the topic lives under .../a+b. The PIP-475
  check in BrokerService#isAllowAutoTopicCreationAsync then misses the
  scalable topic record and would allow recreating a migrated
  persistent topic that the migration is supposed to shadow-protect.

Splice the local name verbatim, matching SegmentTopicName and the rest
of TopicName, which apply Codec.encode only when serializing to REST or
metadata paths.
@nodece nodece changed the title [fix] Derive scalable topic identity from the raw local name [fix][broker] Derive scalable topic identity from the raw local name Sep 21, 2026
@nodece
nodece merged commit c99e438 into apache:master Sep 21, 2026
44 checks passed
@lhotari lhotari added this to the 5.0.0 milestone Oct 1, 2026
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.

3 participants