apache/pulsar · error · IllegalArgumentException
pulsarServiceUrlArray contains duplicated value
Error message
pulsarServiceUrlArray contains duplicated value
What it means
Builder.pulsarServiceUrlArray enforces that all provided cluster URLs are distinct; it uses a HashSet and throws IllegalArgumentException when a duplicate entry is added, since failing over between two identical clusters is pointless and would mask misconfiguration.
Source
Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/SameAuthParamsLookupAutoClusterFailover.java:371
public Builder pulsarServiceUrlArray(String[] pulsarServiceUrlArray) {
if (pulsarServiceUrlArray == null || pulsarServiceUrlArray.length == 0) {
throw new IllegalArgumentException("pulsarServiceUrlArray can not be empty");
}
sameAuthParamsLookupAutoClusterFailover.pulsarServiceUrlArray = pulsarServiceUrlArray;
int pulsarServiceLen = pulsarServiceUrlArray.length;
HashSet<String> uniqueChecker = new HashSet<>();
for (int i = 0; i < pulsarServiceLen; i++) {
String pulsarService = pulsarServiceUrlArray[i];
if (StringUtils.isBlank(pulsarService)) {
throw new IllegalArgumentException("pulsarServiceUrlArray contains a blank value at index " + i);
}
if (pulsarService.startsWith("http") || pulsarService.startsWith("HTTP")) {
throw new IllegalArgumentException("SameAuthParamsLookupAutoClusterFailover does not support HTTP"
+ " protocol pulsar service url so far.");
}
if (!uniqueChecker.add(pulsarService)) {
throw new IllegalArgumentException("pulsarServiceUrlArray contains duplicated value "
+ pulsarServiceUrlArray[i]);
}
}
return this;
}
public SameAuthParamsLookupAutoClusterFailover build() {
String[] pulsarServiceUrlArray = sameAuthParamsLookupAutoClusterFailover.pulsarServiceUrlArray;
if (pulsarServiceUrlArray == null) {
throw new IllegalArgumentException("pulsarServiceUrlArray can not be empty");
}
int pulsarServiceLen = pulsarServiceUrlArray.length;
sameAuthParamsLookupAutoClusterFailover.pulsarServiceStateArray = new PulsarServiceState[pulsarServiceLen];
sameAuthParamsLookupAutoClusterFailover.checkCounterArray = new MutableInt[pulsarServiceLen];
for (int i = 0; i < pulsarServiceLen; i++) {
sameAuthParamsLookupAutoClusterFailover.pulsarServiceStateArray[i] = PulsarServiceState.Healthy;
sameAuthParamsLookupAutoClusterFailover.checkCounterArray[i] = new MutableInt(0);
}View on GitHub (pinned to 820761864e)
Solutions
- Deduplicate the array (e.g. new LinkedHashSet<>(Arrays.asList(urls))) before passing it to the builder.
- Fix the source configuration so each cluster is listed exactly once.
- If deduplication changes behavior you relied on, redesign the cluster list — duplicates are never valid here.
Example fix
// before builder.pulsarServiceUrlArray(cfg.getClusterList().toArray(new String[0])); // may contain dupes // after String[] urls = cfg.getClusterList().stream().distinct().toArray(String[]::new); builder.pulsarServiceUrlArray(urls);
Defensive patterns
Strategy: validation
Validate before calling
String[] urls = cfg.getClusterList().stream().distinct().toArray(String[]::new);
if (urls.length != cfg.getClusterList().size()) {
log.warn("Duplicate cluster URLs removed from configuration");
} Try / catch
try {
builder.pulsarServiceUrlArray(urls);
} catch (IllegalArgumentException e) {
log.error("Duplicate cluster URL in configuration: {}", e.getMessage());
throw new ConfigurationException("Each cluster URL must be unique", e);
} Prevention
- Deduplicate cluster lists (LinkedHashSet) before passing them to the builder.
- Avoid concatenating default and override cluster lists without a merge strategy.
- Normalize URL strings (trim, consistent case) before deduplication checks.
When it happens
Trigger: Calling pulsarServiceUrlArray with the same URL appearing two or more times (exact string match, so also different-case or with a trailing slash vs without), e.g. 'pulsar://a:6650,pulsar://a:6650' from a config merge.
Common situations: Config layering (defaults + overrides) concatenating cluster lists without deduplication; copy-paste duplication when adding a cluster; environment variables appended repeatedly.
Understand the failure class
Background: "Invalid value" and "allowed values are" config errors: what your library rejected and how to fix it — this error's family across 41 libraries.
Related errors
- failoverThreshold must be larger than 0
- recoverThreshold must be larger than 0
- checkHealthyIntervalMs must be larger than 0
- testTopic can not be blank
- pulsarServiceUrlArray can not be empty
AI-assisted analysis of apache/pulsar@820761864e (2026-09-06).
Data as JSON: /api/errors/79c502a61c3aa938.
Report an issue: GitHub.