apache/pulsar · error · IllegalArgumentException
Invalid segment descriptor: expected '<hexStart>-<hexEnd>-<s
Error message
Invalid segment descriptor: expected '<hexStart>-<hexEnd>-<segmentId>', got: '${descriptor}' What it means
For a segment:// topic name, the part after the last '/' must be a descriptor of exactly three dash-separated fields: hash range start (hex), hash range end (hex), and a numeric segment id — '<hexStart>-<hexEnd>-<segmentId>'. Any other dash-segment count throws this IllegalArgumentException.
Source
Thrown at pulsar-common/src/main/java/org/apache/pulsar/common/naming/TopicName.java:211
}
this.tenant = parts.get(0);
this.namespacePortion = parts.get(1);
String rawLocalName = parts.get(2);
// For segment:// domains, split local name into parent topic name + descriptor
if (this.domain == TopicDomain.segment) {
int lastSlash = rawLocalName.lastIndexOf('/');
if (lastSlash <= 0) {
throw new IllegalArgumentException(
"Invalid segment topic name: local name must contain"
+ " '<parent-topic>/<hashStart>-<hashEnd>-<segmentId>'. Got: "
+ completeTopicName);
}
this.localName = rawLocalName.substring(0, lastSlash);
String descriptor = rawLocalName.substring(lastSlash + 1);
String[] descParts = descriptor.split("-");
if (descParts.length != 3) {
throw new IllegalArgumentException(
"Invalid segment descriptor: expected '<hexStart>-<hexEnd>-<segmentId>',"
+ " got: '" + descriptor + "'");
}
this.segmentRange = HashRange.of(
Integer.parseInt(descParts[0], 16),
Integer.parseInt(descParts[1], 16));
this.segmentId = Long.parseLong(descParts[2]);
} else {
this.localName = rawLocalName;
this.segmentRange = null;
this.segmentId = -1;
}
if (this.domain == TopicDomain.segment) {
this.completeTopicName = String.format("%s://%s/%s/%s/%s",
domain, tenant, namespacePortion, localName,
String.format("%04x-%04x-%d", segmentRange.start(), segmentRange.end(), segmentId));
} else {View on GitHub (pinned to 820761864e)
Solutions
- Format the descriptor as '<hexStart>-<hexEnd>-<segmentId>', e.g. '0000-ffff-0' (hash bounds parsed as hex, segment id as decimal)
- Count the dash-separated fields: the descriptor must yield exactly 3 parts
- Build names with the same formatting the parser emits: String.format("%04x-%04x-%d", start, end, segmentId)
Example fix
// before
TopicName.get("segment://tenant/ns/my-topic/0000-ffff");
// after
TopicName.get("segment://tenant/ns/my-topic/0000-ffff-0"); Defensive patterns
Strategy: validation
Validate before calling
static boolean isSegmentDescriptorValid(String descriptor) {
return descriptor != null && descriptor.matches("[0-9a-fA-F]+-[0-9a-fA-F]+-\\d+");
}
static String formatSegmentDescriptor(int hashStart, int hashEnd, long segmentId) {
return String.format("%04x-%04x-%d", hashStart, hashEnd, segmentId);
} Type guard
static boolean isWellFormedSegmentName(String name) {
if (name == null || !name.contains("/")) return false;
return isSegmentDescriptorValid(name.substring(name.lastIndexOf('/') + 1));
} Try / catch
try {
TopicName tn = TopicName.get(segmentTopic);
} catch (IllegalArgumentException e) {
if (e.getMessage().startsWith("Invalid segment descriptor")) {
throw new IllegalArgumentException("Descriptor must be <hexStart>-<hexEnd>-<segmentId>, e.g. 0000-ffff-0");
}
throw e;
} Prevention
- Always format descriptors with String.format("%04x-%04x-%d", start, end, segmentId) instead of manual concatenation
- Remember hash bounds are hex, segment id is decimal — never mix encodings
- Never split or rejoin segment names on '-' with generic string utilities
- Add a regex pre-check ([0-9a-fA-F]+-[0-9a-fA-F]+-\d+) before parsing
When it happens
Trigger: TopicName.get('segment://tenant/ns/topic/abc') (1 field), 'segment://tenant/ns/topic/0000-ffff' (2 fields), or 'segment://tenant/ns/topic/a-b-c-d' (4 fields).
Common situations: Hand-writing segment names without the 3-part descriptor; hash range values accidentally containing extra '-'; generated names corrupted by other '-' splitting logic; typo dropping one of the three fields.
Related errors
- Invalid segment topic name: local name must contain '<parent
- Invalid short topic name '${completeTopicName}', it should b
- V1 topic names (with cluster component) are no longer suppor
- Invalid topic name ${completeTopicName}
- ResourceGroupCreate: Invalid null ResourceGroup config
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/d729631aeb4958d9.
Report an issue: GitHub.