apache/druid · error · IllegalArgumentException

First token should be START_ARRAY, but it is actually [%s]

Error message

First token should be START_ARRAY, but it is actually [%s]

What it means

JsonIterator (prefetch-based JSON input) expects the input stream to be a top-level JSON array so it can iterate elements as rows. If Jackson's first token is anything other than START_ARRAY, it throws this IllegalArgumentException naming the actual token.

Source

Thrown at processing/src/main/java/org/apache/druid/data/input/impl/prefetch/JsonIterator.java:119

      jp.nextToken();
      return retVal;
    }
    catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  private void init()
  {
    try {
      if (inputStream == null) {
        throw new UnsupportedOperationException();
      } else {
        jp = objectMapper.getFactory().createParser(inputStream);
      }
      final JsonToken nextToken = jp.nextToken();
      if (nextToken != JsonToken.START_ARRAY) {
        throw new IAE("First token should be START_ARRAY, but it is actually [%s]", jp.getCurrentToken());
      } else {
        jp.nextToken();
        objectCodec = jp.getCodec();
      }
    }
    catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

  @Override
  public void close() throws IOException
  {
    CloseableUtils.closeAll(jp, resourceCloser);
  }
}

View on GitHub (pinned to 9b90983fd2)

Solutions

  1. Wrap the data in a top-level JSON array ([{...},{...}])
  2. Or use the correct inputFormat for NDJSON data instead of the array-expecting one
  3. Convert the file with jq -s '.' to produce an array
  4. Check the actual token reported in the message to confirm the data shape

Example fix

// before (ndjson)
{"a":1}
{"a":2}
// after (array)
[{"a":1},{"a":2}]
Defensive patterns

Strategy: validation

Validate before calling

try (JsonParser jp = new JsonFactory().createParser(in)) { if (jp.nextToken() != JsonToken.START_ARRAY) { /* not a JSON array */ } }

Type guard

boolean isJsonArray(InputStream in) { try { return new JsonFactory().createParser(in).nextToken() == JsonToken.START_ARRAY; } catch (IOException e) { return false; } }

Try / catch

try { iterator.forEachRemaining(r -> consume(r)); } catch (IllegalArgumentException e) { if (e.getMessage().contains("START_ARRAY")) { /* switch inputFormat */ } }

Prevention

When it happens

Trigger: Pointing a JSON input format at a file whose root is a single JSON object, NDJSON stream, scalar, or other non-array JSON - init() reads the first token and finds e.g. START_OBJECT or VALUE_STRING.

Common situations: NDJSON (newline-delimited objects) files fed where a JSON array is required, single object files, concatenated JSON without wrapping array, wrong inputFormat chosen for the data shape.

Understand the failure class

Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.

Related errors


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