elastic/elasticsearch · error · IllegalStateException

expected value but got

Error message

expected value but got [{token}]

What it means

Thrown by AbstractObjectParser.parseArray while iterating array elements: it only accepts VALUE tokens, VALUE_NULL, or START_OBJECT per element. Any other token (START_ARRAY for nested arrays, FIELD_NAME, END_OBJECT) is rejected as a structural error. This is an IllegalStateException, not an XContentParseException, so it signals the array shape diverged from what the item parser can consume.

Solutions

  1. Inspect the actual token reported in the message and reshape the input so each array element is a scalar, null, or object.
  2. If nested arrays are legitimately expected, switch from parseArray to a custom loop that handles START_ARRAY recursively instead of relying on the shared helper.
  3. Verify the itemParser does not call nextToken() past its element boundary, which would leave the cursor on a FIELD_NAME/END_OBJECT and trip the guard.

Example fix

// before: input is [[1,2],[3,4]] but parser expects [1,2,3,4]
List<Integer> vals = AbstractObjectParser.parseArray(parser, ctx, (c, p) -> p.intValue());

// after: flatten the source, or handle nested arrays explicitly
List<Integer> vals = new ArrayList<>();
while (parser.nextToken() != Token.END_ARRAY) {
    AbstractObjectParser.parseArray(parser, ctx, (c, p) -> { vals.add(p.intValue()); return null; });
}
Defensive patterns

Strategy: validation

Validate before calling

Token t = parser.currentToken();
boolean ok = t == Token.START_ARRAY;
// before iterating: confirm elements are scalars/objects, not nested arrays
if (ok && parser.nextToken() == Token.START_ARRAY) {
    // nested array — do not use parseArray, handle recursively
}

Try / catch

try {
    List<T> items = AbstractObjectParser.parseArray(parser, ctx, itemParser);
} catch (IllegalStateException e) {
    if (e.getMessage().startsWith("expected value but got")) {
        // reshape input or switch to a recursive array reader
    }
}

Prevention

When it happens

Trigger: Feeding a nested array (array-of-arrays) to a parser whose itemParser expects scalar/object elements. Malformed JSON where an object body appears where array elements are expected. A custom ContextParser that advances the cursor inconsistently, leaving the parser positioned on a FIELD_NAME or START_ARRAY inside the loop.

Common situations: Schema drift: a field declared as a flat list starts receiving grouped/nested data after an upstream change. Reusing a parser across mixed shapes. Tests with hand-written JSON that accidentally nests one level too deep.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/0099c62e97ad5b0f. Report an issue: GitHub.

Appendix: source

Thrown at libs/x-content/src/main/java/org/elasticsearch/xcontent/AbstractObjectParser.java:445

     * @param exclusiveSet a set of field names, at most one of which must appear
     */
    public abstract void declareExclusiveFieldSet(String... exclusiveSet);

    public static <T, Context> List<T> parseArray(XContentParser parser, Context context, ContextParser<Context, T> itemParser)
        throws IOException {
        final XContentParser.Token currentToken = parser.currentToken();
        if (currentToken.isValue()
            || currentToken == XContentParser.Token.VALUE_NULL
            || currentToken == XContentParser.Token.START_OBJECT) {
            return Collections.singletonList(itemParser.parse(parser, context)); // single value
        }
        final List<T> list = new ArrayList<>();
        XContentParser.Token token;
        while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) {
            if (token.isValue() || token == XContentParser.Token.VALUE_NULL || token == XContentParser.Token.START_OBJECT) {
                list.add(itemParser.parse(parser, context));
            } else {
                throw new IllegalStateException("expected value but got [" + token + "]");
            }
        }
        return list;
    }
}

View on GitHub (pinned to db6a809a66)