apache/pulsar · error · PulsarServerException

Cannot start the service once it was stopped

Error message

Cannot start the service once it was stopped

What it means

PulsarService.start() acquires a mutex and checks the internal lifecycle State before initializing the broker. The service may only be started once from State.Init; after shutdown() moves the state past Init, calling start() again on the same PulsarService instance throws PulsarServerException. Instances are single-use: to restart, create a new PulsarService.

Source

Thrown at pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java:871

    /**
     * Start the pulsar service instance.
     */
    public void start() throws PulsarServerException {
        log.info()
                .attr("version", (brokerVersion != null ? brokerVersion : "unknown"))
                .attr("gitRevision", PulsarVersion.getGitSha())
                .attr("gitBranch", PulsarVersion.getGitBranch())
                .attr("buildUser", PulsarVersion.getBuildUser())
                .attr("buildHost", PulsarVersion.getBuildHost())
                .attr("buildTime", PulsarVersion.getBuildTime())
                .log("Starting Pulsar Broker service");

        long startTimestamp = System.currentTimeMillis();  // start time mills

        mutex.lock();
        try {
            if (state != State.Init) {
                throw new PulsarServerException("Cannot start the service once it was stopped");
            }

            if (config.getWebServicePort().isEmpty()
                    && config.getWebServicePortTls().isEmpty()
                    && BindAddressValidator.validateBindAddresses(config, Arrays.asList("http", "https")).isEmpty()) {
                throw new IllegalArgumentException(
                        "webServicePort/webServicePortTls or http/https bindAddresses must be present");
            }

            if (config.isAuthorizationEnabled() && !config.isAuthenticationEnabled()) {
                throw new IllegalStateException("Invalid broker configuration. Authentication must be enabled with "
                        + "authenticationEnabled=true when authorization is enabled with authorizationEnabled=true.");
            }

            if (config.getDefaultRetentionSizeInMB() > 0
                    && config.getBacklogQuotaDefaultLimitBytes() > 0
                    && config.getBacklogQuotaDefaultLimitBytes()
                    >= (config.getDefaultRetentionSizeInMB() * 1024L * 1024L)) {

View on GitHub (pinned to 820761864e)

Solutions

  1. Create a new PulsarService instance (with the same configuration) and call start() on it instead of restarting the old one.
  2. Ensure shutdown() is terminal in your code path: after calling close()/shutdown(), discard the reference rather than calling start() again.
  3. Guard restart logic: track whether the instance was already started/stopped, and rebuild the service on restart.
  4. If using PulsarService in tests, wrap setup in a fresh instance per test class/method (or use the testcontainers/mock runners) instead of reusing a stopped instance.

Example fix

// before
pulsarService.shutdown();
pulsarService.start(); // throws: state != Init

// after
pulsarService.shutdown();
PulsarService pulsarService2 = new PulsarService(config);
pulsarService2.start();
Defensive patterns

Strategy: try-catch

Validate before calling

// Track lifecycle yourself; PulsarService state is not publicly queryable.
if (startedOnce && !recreateServiceOnRestart) {
    throw new IllegalStateException("PulsarService is single-use; create a new instance to restart");
}

Try / catch

try {
    pulsarService.start();
} catch (PulsarServerException e) {
    if (e.getMessage().contains("Cannot start the service once it was stopped")) {
        pulsarService = new PulsarService(config); // rebuild instead of restart
        pulsarService.start();
    } else {
        throw e;
    }
}

Prevention

When it happens

Trigger: Calling pulsar.start() on a PulsarService instance whose state != State.Init — typically after a previous start()/shutdown() (state moved to Closed/Stopped), or calling start() twice concurrently/sequentially on the same instance, or a framework (test harness, Spring lifecycle) restarting the same bean after stop.

Common situations: Unit/integration tests that stop the broker then try to restart the same PulsarService object; application code implementing custom restart logic by re-calling start() after an error; lifecycle managers (e.g., Spring @PostConstruct/@PreDestroy, Kafka-style restart handlers) treating PulsarService as restartable.

Related errors


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