apache/druid · error · IllegalStateException
Cannot start; not ready!
Error message
Cannot start; not ready!
What it means
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).
Source
Thrown at indexing-service/src/main/java/org/apache/druid/indexing/common/task/AbstractBatchIndexTask.java:178
/**
* Run this task. Before running the task, it checks the current task is already stopped and
* registers a cleaner to interrupt the thread running this task on abnormal exits.
*
* @see #runTask(TaskToolbox)
* @see #stopGracefully(TaskConfig)
*/
@Override
public String setup(TaskToolbox toolbox) throws Exception
{
if (taskLockHelper == null) {
// Subclasses generally use "isReady" to initialize the taskLockHelper. It's not guaranteed to be called before
// "run", and so we call it here to ensure it happens.
//
// We're only really calling it for its side effects, and we expect it to return "true". If it doesn't, something
// strange is going on, so bail out.
if (!isReady(toolbox.getTaskActionClient())) {
throw new ISE("Cannot start; not ready!");
}
}
synchronized (this) {
if (stopped) {
return "Attempting to run a task that has been stopped. See overlord & task logs for more details.";
} else {
// Register the cleaner to interrupt the current thread first.
// Since the resource closer cleans up the registered resources in LIFO order,
// this will be executed last on abnormal exists.
// The order is sometimes important. For example, Appenderator has two methods of close() and closeNow(), and
// closeNow() is supposed to be called on abnormal exits. Interrupting the current thread could lead to close()
// to be called indirectly, e.g., for Appenderators in try-with-resources. In this case, closeNow() should be
// called before the current thread is interrupted, so that subsequent close() calls can be ignored.
final Thread currentThread = Thread.currentThread();
resourceCloserOnAbnormalExit.register(config -> currentThread.interrupt());
}
}View on GitHub (pinned to 9b90983fd2)
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.
Example fix
// before // task submitted while overlapping batch task still running -> setup() fails // after // wait for/kill the overlapping task, then resubmit: curl -X DELETE http://overlord:8081/druid/indexer/v1/task/<conflictingTaskId>/shutdown
Defensive patterns
Strategy: retry
Validate before calling
// before submitting, check for conflicting active tasks on the same datasource/interval curl -s http://overlord:8081/druid/indexer/v1/tasks | jq '[.[] | select(.dataSource=="my_ds")]'
Try / catch
try {
runTask(task);
} catch (IllegalStateException e) {
if ("Cannot start; not ready!".equals(e.getMessage())) {
// wait for competing tasks to finish, then resubmit
} else throw e;
} Prevention
- 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.
When it happens
Trigger: 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.
Common situations: 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.
Understand the failure class
Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.
Related errors
- Number of locks exceeded maxAllowedLockCount [%s].
- Lock revoked: [%s]
- Cannot find a version for interval[%s]
- Lock dataSource[%s] != task dataSource[%s]
- Can't find surrogate task[%s]
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/9aec8d7bcf340707.
Report an issue: GitHub.