apache/pulsar · error · IllegalStateException

ServiceUrlProvider has already been initialized

Error message

ServiceUrlProvider has already been initialized

What it means

SameAuthParamsLookupAutoClusterFailover is a ServiceUrlProvider that can be attached to exactly one PulsarClient. initialize() throws IllegalStateException if initialize() has already been called successfully, because re-initializing would clobber the existing client reference, executor, and scheduled probe task.

Source

Thrown at pulsar-client/src/main/java/org/apache/pulsar/client/impl/SameAuthParamsLookupAutoClusterFailover.java:78

    @Getter
    private long checkHealthyIntervalMs = 1000;
    @Getter
    private boolean markTopicNotFoundAsAvailable = true;
    @Getter
    private String testTopic = "public/default/tp_test";

    private String[] pulsarServiceUrlArray;
    private PulsarServiceState[] pulsarServiceStateArray;
    private MutableInt[] checkCounterArray;
    @Getter
    private volatile int currentPulsarServiceIndex;

    private SameAuthParamsLookupAutoClusterFailover() {}

    @Override
    public synchronized void initialize(PulsarClient client) {
        if (this.pulsarClient != null) {
            throw new IllegalStateException("ServiceUrlProvider has already been initialized");
        }
        this.currentPulsarServiceIndex = 0;
        this.pulsarClient = (PulsarClientImpl) client;
        this.executor = Executors.newSingleThreadScheduledExecutor(
                new ExecutorProvider.ExtendedThreadFactory("broker-service-url-check"));
        // Use fixed-delay (not fixed-rate) scheduling: a probe can block up to its timeout, and with a
        // plain single-threaded scheduled executor fixed-rate runs would otherwise pile up back-to-back
        // and monopolize the thread. Fixed-delay leaves a gap after each check completes.
        scheduledCheckTask = executor.scheduleWithFixedDelay(() -> {
            try {
                if (closed) {
                    return;
                }
                checkPulsarServices();
                int firstHealthyPulsarService = firstHealthyPulsarService();
                if (firstHealthyPulsarService == currentPulsarServiceIndex) {
                    return;
                }

View on GitHub (pinned to 820761864e)

Solutions

  1. Create a fresh SameAuthParamsLookupAutoClusterFailover instance (via its Builder) for every PulsarClient you construct.
  2. If you must reuse configuration, keep the Builder/config around and build a new provider instead of re-calling initialize on the old one.
  3. Guard your initialization code so initialize() is invoked at most once per provider instance (check your own lifecycle flag).

Example fix

// before
AutoClusterFailoverConfig config = ...;
SameAuthParamsLookupAutoClusterFailover provider = SameAuthParamsLookupAutoClusterFailover.builder()...build();
PulsarClient c1 = PulsarClient.builder().serviceUrlProvider(provider).create();
PulsarClient c2 = PulsarClient.builder().serviceUrlProvider(provider).create(); // throws

// after
PulsarClient c2 = PulsarClient.builder()
    .serviceUrlProvider(SameAuthParamsLookupAutoClusterFailover.builder()...build())
    .create();
Defensive patterns

Strategy: validation

Validate before calling

if (provider instanceof SameAuthParamsLookupAutoClusterFailover
        && isAlreadyInitialized(provider)) {
    provider = SameAuthParamsLookupAutoClusterFailover.builder()...build();
}

Try / catch

try {
    provider.initialize(client);
} catch (IllegalStateException e) {
    // provider already attached to a client: build a new one and retry once
    provider = buildNewProvider(config);
    provider.initialize(client);
}

Prevention

When it happens

Trigger: Calling initialize(client) a second time on the same SameAuthParamsLookupAutoClusterFailover instance, e.g. reusing one builder-produced provider across multiple PulsarClient instances or retrying client construction with the same provider object.

Common situations: Application restart logic that re-creates a PulsarClient but reuses the shared ServiceUrlProvider singleton; configuration reload code that calls initialize again on the same instance instead of building a new one.

Related errors


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