{"record":{"id":"43f957e20e7ccfd8","repo":"elastic/elasticsearch","slug":"required-fields","errorCode":null,"errorMessage":"Required [{fields}]","messagePattern":"Required \\[(.+?)\\]","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/x-content/src/main/java/org/elasticsearch/xcontent/ConstructingObjectParser.java","lineNumber":556,"sourceCode":"            /*\n             * The object hasn't been built which ought to mean we're missing some constructor arguments. But they could be optional! We'll\n             * check if they are all optional and build the error message at the same time - if we don't start the error message then they\n             * were all optional!\n             */\n            StringBuilder message = null;\n            for (int i = 0; i < constructorArgs.length; i++) {\n                if (constructorArgs[i] != null) continue;\n                ConstructorArgInfo arg = constructorArgInfos.get(parser.getRestApiVersion()).get(i);\n                if (false == arg.required) continue;\n                if (message == null) {\n                    message = new StringBuilder(\"Required [\").append(arg.field);\n                } else {\n                    message.append(\", \").append(arg.field);\n                }\n            }\n            if (message != null) {\n                // There were non-optional constructor arguments missing.\n                throw new IllegalArgumentException(message.append(']').toString());\n            }\n            /*\n             * If there weren't any constructor arguments declared at all then we won't get an error message but this isn't really a valid\n             * use of ConstructingObjectParser. You should be using ObjectParser instead. Since this is more of a programmer error and the\n             * parser ought to still work we just assert this.\n             */\n            assert false == constructorArgInfos.isEmpty()\n                : \"[\"\n                    + objectParser.getName()\n                    + \"] must configure at least one constructor \"\n                    + \"argument. If it doesn't have any it should use ObjectParser instead of ConstructingObjectParser. This is a bug \"\n                    + \"in the parser declaration.\";\n            // All missing constructor arguments were optional. Just build the target and return it.\n            buildTarget();\n            return targetObject;\n        }\n\n        private void buildTarget() {","sourceCodeStart":538,"sourceCodeEnd":574,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/x-content/src/main/java/org/elasticsearch/xcontent/ConstructingObjectParser.java#L538-L574","documentation":"After all fields are consumed, ConstructingObjectParser checks each constructor argument slot; any slot still null for a required (non-optional) constructorArg is collected into a comma-separated list and reported. The message enumerates every missing required argument in declaration order. Optional constructor args (optionalConstructorArg) do not trigger this; only required constructorArg() slots do.","triggerScenarios":"Input object omits one or more fields declared with constructorArg() (required). Sending a subset of the required fields, or sending them under deprecated/alternate names not registered, leaves the slot null.","commonSituations":"Client sends a partial request body missing mandatory fields. Field renamed between versions and the old name no longer maps. Test fixtures that don't include all required fields.","solutions":["Add the missing field(s) named in the message to the input object.","If the field is genuinely optional at your call site, declare it with optionalConstructorArg() instead of constructorArg() in the parser definition.","Verify the field name sent matches a registered ParseField (including all deprecated aliases) so the value actually populates the slot."],"exampleFix":"// before: parser requires 'name' and 'type' as constructor args, input omits 'type'\n{\"name\": \"foo\"}\n\n// after\n{\"name\": \"foo\", \"type\": \"bar\"}","handlingStrategy":"validation","validationCode":"// before calling apply(), confirm all required constructor-arg fields are present\nSet<String> required = Set.of(\"name\", \"type\"); // fields declared via constructorArg()\nMap<String,Object> body = parseToMap(parserClone);\nif (!body.keySet().containsAll(required)) {\n    throw new IllegalArgumentException(\"missing required fields: \" + Sets.difference(required, body.keySet()));\n}","typeGuard":null,"tryCatchPattern":"try {\n    Value v = cop.apply(parser, ctx);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().startsWith(\"Required [\")) {\n        // collect missing fields from message and ask the client to supply them\n    }\n}","preventionTips":["Document the required constructor-arg fields in the API/endpoint spec so clients send them.","Validate presence of mandatory fields at the controller layer before delegating to the parser.","Use optionalConstructorArg() for fields that are genuinely optional to avoid over-constraining."],"tags":["xcontent","constructing-object-parser","required-field","deserialization"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}