{"record":{"id":"be8dd3a11d702a23","repo":"elastic/elasticsearch","slug":"clazz-getsimplename-value-passed-as-string","errorCode":null,"errorMessage":"${clazz.getSimpleName()} value passed as String","messagePattern":"(.+?) value passed as String","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"libs/x-content/src/main/java/org/elasticsearch/xcontent/support/AbstractXContentParser.java","lineNumber":48,"sourceCode":"import java.util.List;\nimport java.util.Map;\nimport java.util.function.Supplier;\n\npublic abstract class AbstractXContentParser implements XContentParser {\n\n    // Currently this is not a setting that can be changed and is a policy\n    // that relates to how parsing of things like \"boost\" are done across\n    // the whole of Elasticsearch (eg if String \"1.0\" is a valid float).\n    // The idea behind keeping it as a constant is that we can track\n    // references to this policy decision throughout the codebase and find\n    // and change any code that needs to apply an alternative policy.\n    public static final boolean DEFAULT_NUMBER_COERCE_POLICY = true;\n\n    public static void checkCoerceString(boolean coerce, Class<? extends Number> clazz) {\n        if (coerce == false) {\n            // Need to throw type IllegalArgumentException as current catch logic in\n            // NumberFieldMapper.parseCreateField relies on this for \"malformed\" value detection\n            throw new IllegalArgumentException(clazz.getSimpleName() + \" value passed as String\");\n        }\n    }\n\n    private final NamedXContentRegistry xContentRegistry;\n    private final DeprecationHandler deprecationHandler;\n    private final RestApiVersion restApiVersion;\n\n    public AbstractXContentParser(\n        NamedXContentRegistry xContentRegistry,\n        DeprecationHandler deprecationHandler,\n        RestApiVersion restApiVersion\n    ) {\n        this.xContentRegistry = xContentRegistry;\n        this.deprecationHandler = deprecationHandler;\n        this.restApiVersion = restApiVersion;\n    }\n\n    public AbstractXContentParser(NamedXContentRegistry xContentRegistry, DeprecationHandler deprecationHandler) {","sourceCodeStart":30,"sourceCodeEnd":66,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/libs/x-content/src/main/java/org/elasticsearch/xcontent/support/AbstractXContentParser.java#L30-L66","documentation":"Thrown by AbstractXContentParser.checkCoerceString() when coerce is false and the parser encounters a VALUE_STRING token for a field that expects a Number type. The coercion policy (DEFAULT_NUMBER_COERCE_POLICY=true by default) normally allows strings like \"42\" to be parsed as numbers, but when a caller explicitly disables coercion (coerce=false), any string representation of a number is rejected.","triggerScenarios":"A field mapper with 'coerce: false' in the mapping receiving a JSON string value for a numeric field (e.g., sending \"42\" as a string for an integer field with coercion disabled). Calling shortValue(false), intValue(false), or longValue(false) on the parser when the current token is VALUE_STRING.","commonSituations":"Index settings or field mappings with coerce disabled to enforce strict numeric types. Client library serializing numbers as strings (e.g., JavaScript BigInt or BigDecimal as strings). Sending numeric query parameters as quoted strings.","solutions":["Send the numeric value as a JSON number (no quotes) instead of a string.","If string-to-number coercion is acceptable, enable coerce in the field mapping.","Update the client serializer to emit numbers without quotes for numeric fields.","Validate the JSON payload to ensure numeric fields contain bare numbers, not strings."],"exampleFix":"// before — number sent as string with coerce disabled\nPUT /my-index/_doc/1\n{ \"price\": \"99.99\" }\n\n// after — number sent as JSON number\nPUT /my-index/_doc/1\n{ \"price\": 99.99 }","handlingStrategy":"validation","validationCode":"// Before indexing, verify numeric fields are not passed as strings\npublic static void validateNumericFields(Map<String, Object> doc, Map<String, Class<?>> numericFields) {\n    for (Map.Entry<String, Class<?>> entry : numericFields.entrySet()) {\n        Object val = doc.get(entry.getKey());\n        if (val instanceof String && Number.class.isAssignableFrom(entry.getValue())) {\n            throw new IllegalArgumentException(\n                entry.getKey() + \" must be a number, not a string (coerce is disabled)\"\n            );\n        }\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    parser.shortValue(false); // or intValue/longValue with coerce=false\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"value passed as String\")) {\n        // Re-read the value and handle the coercion error\n        throw new BadRequestException(\"Numeric field received a string value: \" + e.getMessage());\n    }\n    throw e;\n}","preventionTips":["Send numeric values as JSON numbers (unquoted), not as strings, for numeric fields.","If coerce is disabled in the mapping, strictly validate value types client-side.","Use typed serialization (e.g., Jackson with proper numeric types) to avoid quoting numbers."],"tags":["parsing","xcontent","coercion","type-mismatch","numeric"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}