{"record":{"id":"17470c538fe7791d","repo":"apache/druid","slug":"can-t-stop-17470c","errorCode":null,"errorMessage":"can't stop.","messagePattern":"can't stop\\.","errorType":"exception","errorClass":"ISE","httpStatus":null,"severity":"error","filePath":"extensions-core/druid-catalog/src/main/java/org/apache/druid/catalog/sync/CatalogUpdateReceiver.java","lineNumber":112,"sourceCode":"      LOG.info(\"Catalog update receiver started\");\n    }\n    finally {\n      lifecycleLock.exitStart();\n    }\n\n    try {\n      resync();\n    }\n    catch (Throwable t) {\n      LOG.warn(t, \"Failed to perform initial catalog synchronization\");\n    }\n  }\n\n  @LifecycleStop\n  public void stop()\n  {\n    if (!lifecycleLock.canStop()) {\n      throw new ISE(\"can't stop.\");\n    }\n\n    LOG.info(\"Catalog update receiver stopped\");\n    exec.shutdownNow();\n    lifecycleLock.exitStop();\n  }\n\n  private void resync() throws Exception\n  {\n    RetryUtils.retry(\n        () -> {\n          cachedCatalog.resync();\n          return true;\n        },\n        e -> true,\n        config.getMaxSyncRetries()\n    );\n  }","sourceCodeStart":94,"sourceCodeEnd":130,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/druid-catalog/src/main/java/org/apache/druid/catalog/sync/CatalogUpdateReceiver.java#L94-L130","documentation":"CatalogUpdateReceiver.stop() checks lifecycleLock.canStop(); if the receiver was never started, or was already stopped, stopping is illegal and it throws ISE(\"can't stop.\"). It protects the exec executor and lock state from inconsistent shutdown.","triggerScenarios":"Calling stop() on a receiver that was never started; calling stop() twice; calling stop() after shutdown of the enclosing lifecycle.","commonSituations":"Teardown code that unconditionally calls stop() regardless of start success; tests stopping receivers in @AfterAll when start failed; double-close from both component and lifecycle.","solutions":["Only call stop() if start() succeeded; track start state or use try/finally mirroring start.","Manage the receiver through a Lifecycle (addHandler) so start/stop pairing is enforced.","Catch ISE and treat as 'already stopped' in shutdown paths where idempotency is needed.","Fix the earlier start failure that left the receiver never-started instead of suppressing at stop time."],"exampleFix":"// before\nreceiver.stop(); // may throw if never started\n\n// after\nif (started) {\n  receiver.stop();\n  started = false;\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try {\n  receiver.stop();\n} catch (ISE e) {\n  if (\"can't stop.\".equals(e.getMessage())) {\n    // never started or already stopped; ignore or log\n  }\n}","preventionTips":["Stop only after a successful start (track state or use try/finally).","Use Lifecycle handlers so stop pairs with start.","Investigate the start failure that left the receiver unstarted rather than swallowing stop errors.","Make shutdown paths idempotent with caught ISE handling."],"tags":["lifecycle","state","shutdown"],"backgroundTag":"invalid-state-transition","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}