apache/druid · error · IllegalArgumentException

Next token wasn't a START_ARRAY, was

Error message

Next token wasn't a START_ARRAY, was[%s] from url[%s] with value[%s]

What it means

JsonParserIterator expects the HTTP response body to start with a JSON START_ARRAY token (the standard Druid results array). If the first token is anything else, init() throws this IAE showing the actual token type, the URL, and a truncated (192-char) snapshot of the payload. This usually means the server returned an error or non-standard JSON object instead of the expected results array.

Solutions

  1. Read the value[%s] in the message: it usually contains the real server error; fix that underlying issue first
  2. Confirm broker and data node versions are compatible (rolling-upgrade skew can change response shapes)
  3. Check for proxies/load balancers intercepting the URL and returning non-JSON bodies
  4. Retry the query; if persistent, capture the raw response from the data node endpoint for diagnosis
Defensive patterns

Strategy: try-catch

Validate before calling

// verify cluster version skew before issuing queries
// all data nodes should report the same/major-compatible version as the broker

Try / catch

try {
  stream = iterator; // triggers init()
} catch (IAE e) {
  if (e.getMessage().startsWith("Next token wasn't a START_ARRAY")) {
    // log full message: contains upstream error payload in value[...]
    // surface underlying server error, do not blindly retry
  }
}

Prevention

When it happens

Trigger: The response stream from url[%s] parses to a token that is not START_ARRAY — e.g. a JSON error object {"error":...}, a bare string, or HTML from a misbehaving proxy — encountered when hasNext()/next() call init().

Common situations: Downstream server returning a serialized QueryException or plain error JSON, an intermediate proxy/load balancer replacing the body with an HTML error page, or API/protocol mismatch between broker and older/newer data node versions.

Related errors


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

Appendix: source

Thrown at server/src/main/java/org/apache/druid/client/JsonParserIterator.java:202

          // this exception thrown for other reasons, it would be great to document what other reasons this can happen.
          throw ResourceLimitExceededException.withMessage(
              "Possibly max scatter-gather bytes limit reached while reading from url[%s].",
              url
          );
        }

        final JsonToken nextToken = jp.nextToken();
        if (nextToken == JsonToken.START_ARRAY) {
          jp.nextToken();
          objectCodec = jp.getCodec();
        } else if (nextToken == JsonToken.START_OBJECT) {
          throw convertException(jp.getCodec().readValue(jp, QueryException.class));
        } else {
          String errMsg = jp.getValueAsString();
          if (errMsg != null) {
            errMsg = errMsg.substring(0, Math.min(errMsg.length(), 192));
          }
          throw convertException(
              new IAE(
                  "Next token wasn't a START_ARRAY, was[%s] from url[%s] with value[%s]",
                  jp.getCurrentToken(),
                  url,
                  errMsg
              )
          );
        }
      }
      catch (ExecutionException | CancellationException e) {
        throw convertException(e.getCause() == null ? e : e.getCause());
      }
      catch (IOException | InterruptedException e) {
        throw convertException(e);
      }
      catch (TimeoutException e) {
        throw new QueryTimeoutException(StringUtils.nonStrictFormat("Query [%s] timed out!", queryId), host);
      }

View on GitHub (pinned to 9b90983fd2)