elastic/elasticsearch · error · XContentParseException
Failed to parse list: expecting ${XContentParser.Token.STAR
Error message
Failed to parse list: expecting ${XContentParser.Token.START_ARRAY} but got ${token} What it means
Thrown by AbstractXContentParser.skipToListStart when the parser is asked to read a list (via list() or listOrderedMap()) but, after skipping an optional FIELD_NAME token, the current token is not START_ARRAY. The parser expected the JSON position to be at (or just before) an array but found a scalar, object, or end token instead.
Source
Thrown at libs/x-content/src/main/java/org/elasticsearch/xcontent/support/AbstractXContentParser.java:451
}
if (token == XContentParser.Token.START_OBJECT) {
return parser.nextFieldName();
}
return token == Token.FIELD_NAME ? parser.currentName() : null;
}
// Skips the current parser to the next array start. Assumes that the parser is either positioned before an array field's name token or
// on the start array token.
private static void skipToListStart(XContentParser parser) throws IOException {
Token token = parser.currentToken();
if (token == null) {
token = parser.nextToken();
}
if (token == XContentParser.Token.FIELD_NAME) {
token = parser.nextToken();
}
if (token != XContentParser.Token.START_ARRAY) {
throw new XContentParseException(
parser.getTokenLocation(),
"Failed to parse list: expecting " + XContentParser.Token.START_ARRAY + " but got " + token
);
}
}
// read a list without bounds checks, assuming the current parser is always on an array start
private static List<Object> readListUnsafe(XContentParser parser, Supplier<Map<String, Object>> mapFactory) throws IOException {
assert parser.currentToken() == Token.START_ARRAY;
ArrayList<Object> list = new ArrayList<>();
for (Token token = parser.nextToken(); token != null && token != XContentParser.Token.END_ARRAY; token = parser.nextToken()) {
list.add(readValueUnsafe(token, parser, mapFactory));
}
return list;
}
public static Object readValue(XContentParser parser, Supplier<Map<String, Object>> mapFactory) throws IOException {
return readValueUnsafe(parser.currentToken(), parser, mapFactory);View on GitHub (pinned to db6a809a66)
Solutions
- Normalize the producer to always emit the field as an array (even single-element arrays).
- In manual parser code, check currentToken() before calling list() and handle VALUE_*/START_OBJECT branches explicitly.
- Use the parser's `ensureExpectedToken` or token-aware helpers to guard list reads.
- If you do not control the producer, pre-process the JSON to wrap scalars in arrays.
Example fix
// before: list() called on a scalar token
Token t = parser.currentToken();
List<Object> items = parser.list();
// after: guard the token
Token t = parser.currentToken();
if (t != Token.START_ARRAY) { throw new IllegalArgumentException("expected array at " + parser.getTokenLocation()); }
List<Object> items = parser.list(); Defensive patterns
Strategy: type-guard
Validate before calling
if (parser.currentToken() != XContentParser.Token.START_ARRAY) {
// materialize a single value as a one-element list, or fail fast
throw new IllegalStateException("expected array, got " + parser.currentToken());
} Type guard
boolean isAtArrayStart(XContentParser p) {
XContentParser.Token t = p.currentToken();
if (t == XContentParser.Token.FIELD_NAME) {
try { return p.nextToken() == XContentParser.Token.START_ARRAY; }
catch (IOException e) { return false; }
}
return t == XContentParser.Token.START_ARRAY;
} Prevention
- Always check currentToken() before calling list()/listOrderedMap().
- Normalize producers to always emit arrays for fields parsed as lists.
- Use ensureExpectedToken helpers from the parser API.
When it happens
Trigger: Calling XContentParser.list() while positioned on a VALUE_STRING, VALUE_NUMBER, START_OBJECT, END_OBJECT, or null token. Reached when application code assumes a field is an array but the JSON contains a single scalar value, or when parsing logic advances the parser incorrectly before the list read.
Common situations: Documents where a field is sometimes a single value and sometimes an array (JSON's single-vs-array ambiguity). Hand-written XContent parsing code that mishandles token positioning. Custom ingest/rest handlers reading configuration that was serialized as an object instead of an array. Migration of mappings where the field shape changed.
Understand the failure class
- Parsing and encoding errors: unexpected token, malformed input — why parsers reject input and how to find the real culprit.
Related errors
- expected value but got [{token}]
- [{}] Expected START_OBJECT but was: {}
- Required one of fields {}, but none were specified.
- The following fields are not allowed together: {}
- [{}] failed to parse object
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/bb6e2929f89973b8.
Report an issue: GitHub.