elastic/elasticsearch · error · XContentParseException

[{}] Expected START_OBJECT but was: {}

Error message

[{}] Expected START_OBJECT but was: {}

What it means

Thrown when ObjectParser.parse() is called and the first token from XContentParser is not START_OBJECT. ObjectParser expects to read a JSON/YAML object (opening brace '{') as its top-level structure; any other leading token (START_ARRAY, VALUE_STRING, VALUE_NUMBER, END_OBJECT, etc.) triggers this error via throwExpectedStartObject.

Source

Thrown at libs/x-content/src/main/java/org/elasticsearch/xcontent/ObjectParser.java:331

                    maybeMarkExclusiveField(currentFieldName, exclusiveFields);
                }

                parseSub(parser, fieldParser, token, currentFieldName, value, context);
            }
        }

        // Check for a) multiple entries appearing in exclusive field sets and b) empty required field entries
        if (exclusiveFields != null) {
            ensureExclusiveFields(exclusiveFields);
        }
        if (requiredFields != null && requiredFields.isEmpty() == false) {
            throwMissingRequiredFields(requiredFields);
        }
        return value;
    }

    private void throwExpectedStartObject(XContentParser parser, XContentParser.Token token) {
        throw new XContentParseException(parser.getTokenLocation(), "[" + name + "] Expected START_OBJECT but was: " + token);
    }

    private static void throwMissingRequiredFields(List<String[]> requiredFields) {
        final StringBuilder message = new StringBuilder();
        for (int i = 0; i < requiredFields.size(); i++) {
            if (i > 0) {
                message.append(" ");
            }
            message.append("Required one of fields ").append(Arrays.toString(requiredFields.get(i))).append(", but none were specified.");
        }
        throw new IllegalArgumentException(message.toString());
    }

    private static void ensureExclusiveFields(List<List<String>> exclusiveFields) {
        StringBuilder message = null;
        for (List<String> fieldset : exclusiveFields) {
            if (fieldset.size() > 1) {
                if (message == null) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Ensure the request body is a JSON object starting with '{' and not an array or scalar.
  2. If the endpoint accepts an array, use the appropriate array-aware parser or endpoint variant.
  3. Validate the body with a JSON linter before sending.
  4. Check for double-wrapping (e.g., body already has outer braces but the client adds another layer).

Example fix

// before — array passed where object expected
POST /_search
[{"query": {"match_all": {}}}]

// after — single object
POST /_search
{"query": {"match_all": {}}}
Defensive patterns

Strategy: validation

Validate before calling

// Before parsing, verify the first non-whitespace character is '{'
public static void ensureStartObject(String json) {
    String trimmed = json.strip();
    if (!trimmed.startsWith("{")) {
        throw new IllegalArgumentException("Expected a JSON object starting with '{'");
    }
}

Try / catch

try {
    return objectParser.apply(parser, context);
} catch (XContentParseException e) {
    if (e.getMessage().contains("Expected START_OBJECT")) {
        return ResponseEntity.badRequest().body(e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: Passing a JSON array where the parser expects an object, e.g., sending [{"field":"value"}] to a REST endpoint whose body schema is a single object. Passing a bare scalar (string, number, boolean) where an object body is required. Sending malformed JSON that causes the tokenizer to emit an unexpected first token.

Common situations: Wrapping a request body in square brackets instead of curly braces. Sending a plain string or number to an endpoint that expects an object. A proxy or load balancer rewriting the body. YAML content where indentation produces an unexpected first token.

Related errors


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