{"record":{"id":"25ad99efaad9b96f","repo":"apache/pulsar","slug":"cannot-start-the-service-once-it-was-stopped","errorCode":null,"errorMessage":"Cannot start the service once it was stopped","messagePattern":"Cannot start the service once it was stopped","errorType":"exception","errorClass":"PulsarServerException","httpStatus":null,"severity":"error","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java","lineNumber":871,"sourceCode":"    /**\n     * Start the pulsar service instance.\n     */\n    public void start() throws PulsarServerException {\n        log.info()\n                .attr(\"version\", (brokerVersion != null ? brokerVersion : \"unknown\"))\n                .attr(\"gitRevision\", PulsarVersion.getGitSha())\n                .attr(\"gitBranch\", PulsarVersion.getGitBranch())\n                .attr(\"buildUser\", PulsarVersion.getBuildUser())\n                .attr(\"buildHost\", PulsarVersion.getBuildHost())\n                .attr(\"buildTime\", PulsarVersion.getBuildTime())\n                .log(\"Starting Pulsar Broker service\");\n\n        long startTimestamp = System.currentTimeMillis();  // start time mills\n\n        mutex.lock();\n        try {\n            if (state != State.Init) {\n                throw new PulsarServerException(\"Cannot start the service once it was stopped\");\n            }\n\n            if (config.getWebServicePort().isEmpty()\n                    && config.getWebServicePortTls().isEmpty()\n                    && BindAddressValidator.validateBindAddresses(config, Arrays.asList(\"http\", \"https\")).isEmpty()) {\n                throw new IllegalArgumentException(\n                        \"webServicePort/webServicePortTls or http/https bindAddresses must be present\");\n            }\n\n            if (config.isAuthorizationEnabled() && !config.isAuthenticationEnabled()) {\n                throw new IllegalStateException(\"Invalid broker configuration. Authentication must be enabled with \"\n                        + \"authenticationEnabled=true when authorization is enabled with authorizationEnabled=true.\");\n            }\n\n            if (config.getDefaultRetentionSizeInMB() > 0\n                    && config.getBacklogQuotaDefaultLimitBytes() > 0\n                    && config.getBacklogQuotaDefaultLimitBytes()\n                    >= (config.getDefaultRetentionSizeInMB() * 1024L * 1024L)) {","sourceCodeStart":853,"sourceCodeEnd":889,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/PulsarService.java#L853-L889","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Create a new PulsarService instance (with the same configuration) and call start() on it instead of restarting the old one.","Ensure shutdown() is terminal in your code path: after calling close()/shutdown(), discard the reference rather than calling start() again.","Guard restart logic: track whether the instance was already started/stopped, and rebuild the service on restart.","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."],"exampleFix":"// before\npulsarService.shutdown();\npulsarService.start(); // throws: state != Init\n\n// after\npulsarService.shutdown();\nPulsarService pulsarService2 = new PulsarService(config);\npulsarService2.start();","handlingStrategy":"try-catch","validationCode":"// Track lifecycle yourself; PulsarService state is not publicly queryable.\nif (startedOnce && !recreateServiceOnRestart) {\n    throw new IllegalStateException(\"PulsarService is single-use; create a new instance to restart\");\n}","typeGuard":null,"tryCatchPattern":"try {\n    pulsarService.start();\n} catch (PulsarServerException e) {\n    if (e.getMessage().contains(\"Cannot start the service once it was stopped\")) {\n        pulsarService = new PulsarService(config); // rebuild instead of restart\n        pulsarService.start();\n    } else {\n        throw e;\n    }\n}","preventionTips":["Treat PulsarService as non-restartable: one start() per instance; rebuild for restarts.","In lifecycle managers, implement restart() as close() + new PulsarService(config).start().","Avoid calling start() from multiple threads; the internal mutex serializes but does not make restart legal.","In tests, create a fresh service per test lifecycle hook instead of reusing stopped instances."],"tags":["lifecycle","state-machine","pulsarservice","illegal-restart","broker"],"backgroundTag":"service-already-stopped","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}