{"record":{"id":"9aec8d7bcf340707","repo":"apache/druid","slug":"cannot-start-not-ready","errorCode":null,"errorMessage":"Cannot start; not ready!","messagePattern":"Cannot start; not ready!","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"indexing-service/src/main/java/org/apache/druid/indexing/common/task/AbstractBatchIndexTask.java","lineNumber":178,"sourceCode":"\n  /**\n   * Run this task. Before running the task, it checks the current task is already stopped and\n   * registers a cleaner to interrupt the thread running this task on abnormal exits.\n   *\n   * @see #runTask(TaskToolbox)\n   * @see #stopGracefully(TaskConfig)\n   */\n  @Override\n  public String setup(TaskToolbox toolbox) throws Exception\n  {\n    if (taskLockHelper == null) {\n      // Subclasses generally use \"isReady\" to initialize the taskLockHelper. It's not guaranteed to be called before\n      // \"run\", and so we call it here to ensure it happens.\n      //\n      // We're only really calling it for its side effects, and we expect it to return \"true\". If it doesn't, something\n      // strange is going on, so bail out.\n      if (!isReady(toolbox.getTaskActionClient())) {\n        throw new ISE(\"Cannot start; not ready!\");\n      }\n    }\n\n    synchronized (this) {\n      if (stopped) {\n        return \"Attempting to run a task that has been stopped. See overlord & task logs for more details.\";\n      } else {\n        // Register the cleaner to interrupt the current thread first.\n        // Since the resource closer cleans up the registered resources in LIFO order,\n        // this will be executed last on abnormal exists.\n        // The order is sometimes important. For example, Appenderator has two methods of close() and closeNow(), and\n        // closeNow() is supposed to be called on abnormal exits. Interrupting the current thread could lead to close()\n        // to be called indirectly, e.g., for Appenderators in try-with-resources. In this case, closeNow() should be\n        // called before the current thread is interrupted, so that subsequent close() calls can be ignored.\n        final Thread currentThread = Thread.currentThread();\n        resourceCloserOnAbnormalExit.register(config -> currentThread.interrupt());\n      }\n    }","sourceCodeStart":160,"sourceCodeEnd":196,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/indexing-service/src/main/java/org/apache/druid/indexing/common/task/AbstractBatchIndexTask.java#L160-L196","documentation":"AbstractBatchIndexTask.setup calls isReady(...) purely for its side effects (initializing taskLockHelper) before running the task, expecting it to return true. If isReady returns false — meaning the task cannot acquire its required locks or its preconditions are unmet — the task cannot start, so this ISE is thrown. Subclasses define readiness (usually: no conflicting locks exist for my intervals).","triggerScenarios":"Running a batch task whose isReady() returns false because another task holds a conflicting lock for the same datasource/interval, or a subclass whose isReady was overridden to return false for incomplete initialization.","commonSituations":"Submitting a compaction or batch ingestion task while an earlier overlapping task still holds locks; two tasks targeting the same time chunk concurrently; stale locks left after an overlord failover.","solutions":["Check competing tasks: GET /druid/indexer/v1/tasks and look for active tasks on the same datasource/interval; wait for or kill them, then retry the task.","Inspect task locks via the overlord locking endpoints and clear stale locks (restart overlord or wait for lock expiry).","If a custom task subclass, ensure isReady() returns true after initialization and doesn't permanently return false.","Retry the task after the conflicting task completes; Druid usually queues/retries automatically when locks are unavailable."],"exampleFix":"// before\n// task submitted while overlapping batch task still running -> setup() fails\n// after\n// wait for/kill the overlapping task, then resubmit:\ncurl -X DELETE http://overlord:8081/druid/indexer/v1/task/<conflictingTaskId>/shutdown","handlingStrategy":"retry","validationCode":"// before submitting, check for conflicting active tasks on the same datasource/interval\ncurl -s http://overlord:8081/druid/indexer/v1/tasks | jq '[.[] | select(.dataSource==\"my_ds\")]'","typeGuard":null,"tryCatchPattern":"try {\n  runTask(task);\n} catch (IllegalStateException e) {\n  if (\"Cannot start; not ready!\".equals(e.getMessage())) {\n    // wait for competing tasks to finish, then resubmit\n  } else throw e;\n}","preventionTips":["Don't run overlapping batch/compaction tasks on the same datasource intervals.","Set task priorities so important writers win lock contention deterministically.","Check /druid/indexer/v1/locking for stale locks after overlord restarts."],"tags":["indexing-service","task-lifecycle","locks"],"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"}