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

  1. Deduplicate the array (e.g. new LinkedHashSet<>(Arrays.asList(urls))) before passing it to the builder.
  2. Fix the source configuration so each cluster is listed exactly once.
  3. 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

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


AI-assisted analysis of apache/pulsar@820761864e (2026-09-06). Data as JSON: /api/errors/79c502a61c3aa938. Report an issue: GitHub.