{"record":{"id":"d4f7798ca47891b8","repo":"elastic/elasticsearch","slug":"expected-start-object-but-was","errorCode":null,"errorMessage":"[{}] Expected START_OBJECT but was: {}","messagePattern":"\\[(.+?)\\] Expected START_OBJECT but was: (.+?)","errorType":"exception","errorClass":"XContentParseException","httpStatus":null,"severity":"error","filePath":"libs/x-content/src/main/java/org/elasticsearch/xcontent/ObjectParser.java","lineNumber":331,"sourceCode":"                    maybeMarkExclusiveField(currentFieldName, exclusiveFields);\n                }\n\n                parseSub(parser, fieldParser, token, currentFieldName, value, context);\n            }\n        }\n\n        // Check for a) multiple entries appearing in exclusive field sets and b) empty required field entries\n        if (exclusiveFields != null) {\n            ensureExclusiveFields(exclusiveFields);\n        }\n        if (requiredFields != null && requiredFields.isEmpty() == false) {\n            throwMissingRequiredFields(requiredFields);\n        }\n        return value;\n    }\n\n    private void throwExpectedStartObject(XContentParser parser, XContentParser.Token token) {\n        throw new XContentParseException(parser.getTokenLocation(), \"[\" + name + \"] Expected START_OBJECT but was: \" + token);\n    }\n\n    private static void throwMissingRequiredFields(List<String[]> requiredFields) {\n        final StringBuilder message = new StringBuilder();\n        for (int i = 0; i < requiredFields.size(); i++) {\n            if (i > 0) {\n                message.append(\" \");\n            }\n            message.append(\"Required one of fields \").append(Arrays.toString(requiredFields.get(i))).append(\", but none were specified.\");\n        }\n        throw new IllegalArgumentException(message.toString());\n    }\n\n    private static void ensureExclusiveFields(List<List<String>> exclusiveFields) {\n        StringBuilder message = null;\n        for (List<String> fieldset : exclusiveFields) {\n            if (fieldset.size() > 1) {\n                if (message == null) {","sourceCodeStart":313,"sourceCodeEnd":349,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/x-content/src/main/java/org/elasticsearch/xcontent/ObjectParser.java#L313-L349","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Ensure the request body is a JSON object starting with '{' and not an array or scalar.","If the endpoint accepts an array, use the appropriate array-aware parser or endpoint variant.","Validate the body with a JSON linter before sending.","Check for double-wrapping (e.g., body already has outer braces but the client adds another layer)."],"exampleFix":"// before — array passed where object expected\nPOST /_search\n[{\"query\": {\"match_all\": {}}}]\n\n// after — single object\nPOST /_search\n{\"query\": {\"match_all\": {}}}","handlingStrategy":"validation","validationCode":"// Before parsing, verify the first non-whitespace character is '{'\npublic static void ensureStartObject(String json) {\n    String trimmed = json.strip();\n    if (!trimmed.startsWith(\"{\")) {\n        throw new IllegalArgumentException(\"Expected a JSON object starting with '{'\");\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    return objectParser.apply(parser, context);\n} catch (XContentParseException e) {\n    if (e.getMessage().contains(\"Expected START_OBJECT\")) {\n        return ResponseEntity.badRequest().body(e.getMessage());\n    }\n    throw e;\n}","preventionTips":["Validate that request bodies are JSON objects, not arrays, before sending to object-expecting endpoints.","Use JSON schema validation on the request body to enforce object root type.","Test API calls with a JSON linter or validator before deploying to production."],"tags":["parsing","xcontent","structure","object-parser","start-object"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}