{"record":{"id":"8e2fc4e2cbfe80ca","repo":"elastic/elasticsearch","slug":"doesn-t-support-arrays-use-a-single-object-w","errorCode":null,"errorMessage":"[{}] doesn't support arrays. Use a single object with multiple fields.","messagePattern":"\\[(.+?)\\] doesn't support arrays\\. Use a single object with multiple fields\\.","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/x-content/src/main/java/org/elasticsearch/xcontent/ObjectParser.java","lineNumber":568,"sourceCode":"        );\n    }\n\n    private static XContentParseException wrapParseError(ParseField field, XContentParser p, IOException e, String s) {\n        return new XContentParseException(p.getTokenLocation(), \"[\" + field + \"] \" + s, e);\n    }\n\n    private static XContentParseException rethrowFieldParseFailure(ParseField field, XContentParser p, String currentName, Exception e) {\n        return new XContentParseException(p.getTokenLocation(), \"[\" + field + \"] failed to parse field [\" + currentName + \"]\", e);\n    }\n\n    @Override\n    public <T> void declareNamedObjects(\n        BiConsumer<Value, List<T>> consumer,\n        NamedObjectParser<T, Context> namedObjectParser,\n        ParseField field\n    ) {\n        Consumer<Value> orderedModeCallback = (v) -> {\n            throw new IllegalArgumentException(\"[\" + field + \"] doesn't support arrays. Use a single object with multiple fields.\");\n        };\n        declareNamedObjects(consumer, namedObjectParser, orderedModeCallback, field);\n    }\n\n    /**\n     * Functional interface for instantiating and parsing named objects. See ObjectParserTests#NamedObject for the canonical way to\n     * implement this for objects that themselves have a parser.\n     */\n    @FunctionalInterface\n    public interface NamedObjectParser<T, Context> {\n        T parse(XContentParser p, Context c, String name) throws IOException;\n    }\n\n    /**\n     * Get the name of the parser.\n     */\n    @Override\n    public String getName() {","sourceCodeStart":550,"sourceCodeEnd":586,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/x-content/src/main/java/org/elasticsearch/xcontent/ObjectParser.java#L550-L586","documentation":"Thrown when declareNamedObjects is invoked with the 3-argument overload (no ordered-mode callback), and the parser then encounters a JSON array at the field position. Named objects in this library must be represented as a JSON object whose keys are the object names; the default ordered-mode callback rejects arrays because it has no way to assign names to array elements.","triggerScenarios":"Sending a JSON array for a field whose ObjectParser was declared with the 3-argument declareNamedObjects (unordered mode). For example, an API that expects {\"name1\": {...}, \"name2\": {...}} but receives [{...}, {...}].","commonSituations":"Client library serializing a list as a JSON array when the server expects a map. Copying an array-based format from one API into another that uses object-based named objects. Misreading the API docs and assuming arrays are accepted.","solutions":["Change the JSON array to an object whose keys are the named-object identifiers.","If the endpoint truly supports arrays, ensure the server-side parser uses the 4-argument declareNamedObjects with an ordered-mode callback.","Update the client serializer to produce a keyed object for this field."],"exampleFix":"// before — array of named objects (rejected)\n{\n  \"aggregations\": [\n    { \"name\": \"agg1\", \"type\": \"terms\" }\n  ]\n}\n\n// after — object with named keys\n{\n  \"aggregations\": {\n    \"agg1\": { \"terms\": { \"field\": \"cat\" } }\n  }\n}","handlingStrategy":"validation","validationCode":"// Before sending, verify named-object fields are objects not arrays\npublic static void ensureNamedObjectsAreMaps(String json) throws Exception {\n    JsonNode root = new ObjectMapper().readTree(json);\n    for (String field : namedObjectFields) {\n        if (root.has(field) && root.get(field).isArray()) {\n            throw new IllegalArgumentException(field + \" must be an object, not an array\");\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    objectParser.parse(parser, context);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"doesn't support arrays\")) {\n        return badRequest(e.getMessage());\n    }\n    throw e;\n}","preventionTips":["Serialize named-object collections as keyed maps in client code, not as arrays.","Review the API spec for each field: object-keyed vs array-ordered.","If the endpoint supports arrays, ensure the server uses the 4-arg declareNamedObjects."],"tags":["parsing","xcontent","named-object","array-misuse","object-parser"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}