elastic/elasticsearch · error · IllegalArgumentException

${clazz.getSimpleName()} value passed as String

Error message

${clazz.getSimpleName()} value passed as String

What it means

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.

Source

Thrown at libs/x-content/src/main/java/org/elasticsearch/xcontent/support/AbstractXContentParser.java:48

import java.util.List;
import java.util.Map;
import java.util.function.Supplier;

public abstract class AbstractXContentParser implements XContentParser {

    // Currently this is not a setting that can be changed and is a policy
    // that relates to how parsing of things like "boost" are done across
    // the whole of Elasticsearch (eg if String "1.0" is a valid float).
    // The idea behind keeping it as a constant is that we can track
    // references to this policy decision throughout the codebase and find
    // and change any code that needs to apply an alternative policy.
    public static final boolean DEFAULT_NUMBER_COERCE_POLICY = true;

    public static void checkCoerceString(boolean coerce, Class<? extends Number> clazz) {
        if (coerce == false) {
            // Need to throw type IllegalArgumentException as current catch logic in
            // NumberFieldMapper.parseCreateField relies on this for "malformed" value detection
            throw new IllegalArgumentException(clazz.getSimpleName() + " value passed as String");
        }
    }

    private final NamedXContentRegistry xContentRegistry;
    private final DeprecationHandler deprecationHandler;
    private final RestApiVersion restApiVersion;

    public AbstractXContentParser(
        NamedXContentRegistry xContentRegistry,
        DeprecationHandler deprecationHandler,
        RestApiVersion restApiVersion
    ) {
        this.xContentRegistry = xContentRegistry;
        this.deprecationHandler = deprecationHandler;
        this.restApiVersion = restApiVersion;
    }

    public AbstractXContentParser(NamedXContentRegistry xContentRegistry, DeprecationHandler deprecationHandler) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Send the numeric value as a JSON number (no quotes) instead of a string.
  2. If string-to-number coercion is acceptable, enable coerce in the field mapping.
  3. Update the client serializer to emit numbers without quotes for numeric fields.
  4. Validate the JSON payload to ensure numeric fields contain bare numbers, not strings.

Example fix

// before — number sent as string with coerce disabled
PUT /my-index/_doc/1
{ "price": "99.99" }

// after — number sent as JSON number
PUT /my-index/_doc/1
{ "price": 99.99 }
Defensive patterns

Strategy: validation

Validate before calling

// Before indexing, verify numeric fields are not passed as strings
public static void validateNumericFields(Map<String, Object> doc, Map<String, Class<?>> numericFields) {
    for (Map.Entry<String, Class<?>> entry : numericFields.entrySet()) {
        Object val = doc.get(entry.getKey());
        if (val instanceof String && Number.class.isAssignableFrom(entry.getValue())) {
            throw new IllegalArgumentException(
                entry.getKey() + " must be a number, not a string (coerce is disabled)"
            );
        }
    }
}

Try / catch

try {
    parser.shortValue(false); // or intValue/longValue with coerce=false
} catch (IllegalArgumentException e) {
    if (e.getMessage().contains("value passed as String")) {
        // Re-read the value and handle the coercion error
        throw new BadRequestException("Numeric field received a string value: " + e.getMessage());
    }
    throw e;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


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