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
- Wrap the data in a top-level JSON array ([{...},{...}])
- Or use the correct inputFormat for NDJSON data instead of the array-expecting one
- Convert the file with jq -s '.' to produce an array
- 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
- Ensure data files are wrapped in a top-level JSON array
- Use the NDJSON-appropriate inputFormat for newline-delimited objects
- Spot-check the first bytes of files before ingestion
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
- '%s' must be a string or an array of strings
- Must provide at least one range
- columnNames and columnTypes must be the same length
- Invalid format specification
- must have an even number of arguments
AI-assisted analysis of apache/druid@9b90983fd2 (2026-09-07).
Data as JSON: /api/errors/5c8faaf715114a7d.
Report an issue: GitHub.