apache/druid · error · IllegalStateException

Unrecognized state[ ] found.

Error message

Unrecognized state[%s] found.

What it means

SqlStatementState is derived from the underlying controller task's status; getSqlStatementState's switch exhaustively maps known states and throws ISE for anything unrecognized, guarding against future/unknown task states.

Solutions

  1. Upgrade all Druid nodes to a consistent version so state enums match
  2. Check the actual task state via the tasks API and re-poll
  3. If a transient/corrupt status, re-fetch the task status
Defensive patterns

Strategy: try-catch

Validate before calling

// only re-poll when the raw state is a known one
Set<String> known = Set.of("RUNNING","SUCCESS","FAILED","PENDING","CANCELED");
if (!known.contains(rawState)) { scheduleRepoll(); }

Try / catch

try {
  state = SqlStatementResourceHelper.getSqlStatementState(status);
} catch (ISE e) {
  // unknown state (version skew); re-poll or upgrade cluster
}

Prevention

When it happens

Trigger: The MSQ controller task reports a state not in the enum mapping (e.g. a new state added in a newer Druid version while an older broker parses it, or a corrupt/foreign status payload).

Common situations: Rolling upgrades with mixed broker/task-node versions; querying a task whose status JSON contains an unexpected state value.

Understand the failure class

Background: Invalid enum value errors: "Unknown type", "Invalid scope", "must be one of" — when a string is not on the library's allowed list — this error's family across 23 libraries.

Related errors


AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07). Data as JSON: /api/errors/77aaa3cd44960d27. Report an issue: GitHub.

Appendix: source

Thrown at multi-stage-query/src/main/java/org/apache/druid/msq/util/SqlStatementResourceHelper.java:142

  {
    TaskState state = taskStatusPlus.getStatusCode();
    if (state == null) {
      return SqlStatementState.ACCEPTED;
    }

    switch (state) {
      case FAILED:
        return SqlStatementState.FAILED;
      case RUNNING:
        if (TaskLocation.unknown().equals(taskStatusPlus.getLocation())) {
          return SqlStatementState.ACCEPTED;
        } else {
          return SqlStatementState.RUNNING;
        }
      case SUCCESS:
        return SqlStatementState.SUCCESS;
      default:
        throw new ISE("Unrecognized state[%s] found.", state);
    }
  }

  /**
   * Populates pages list from the {@link CounterSnapshotsTree}.
   * <br>
   * The number of pages changes with respect to the destination
   * <ol>
   *   <li>{@link DataSourceMSQDestination} a single page is returned which adds all the counters of {@link SegmentGenerationProgressCounter.Snapshot}</li>
   *   <li>{@link TaskReportMSQDestination} a single page is returned which adds all the counters of {@link ChannelCounters}</li>
   *   <li>{@link DurableStorageMSQDestination} a page is returned for each partition, worker which has generated output rows. The pages are populated in the following order:
   *   <ul>
   *     <li>For each partition from 0 to N</li>
   *     <li>For each worker from 0 to M</li>
   *     <li>If num rows for that partition,worker combination is 0, create a page</li>
   *     so that we maintain the record ordering.
   *   </ul>
   * </ol>

View on GitHub (pinned to 9b90983fd2)