elastic/elasticsearch · error · IllegalArgumentException

Value [${stringValue}] has a decimal part

Error message

Value [${stringValue}] has a decimal part

What it means

Thrown by AbstractXContentParser.toLong when coerce=false and the parsed BigDecimal has a fractional part that cannot be losslessly converted to an integer. The ArithmeticException from toBigIntegerExact() (or the explicit scale>19 branch) is caught and re-thrown as this IllegalArgumentException. It enforces strict (non-coercing) long parsing semantics.

Source

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

        try {
            final BigDecimal bigDecimalValue = new BigDecimal(stringValue);
            // long can have a maximum of 19 digits - any more than that cannot be a long
            // the scale is stored as the negation, so negative scale -> big number
            if (bigDecimalValue.scale() < -19) {
                throw new IllegalArgumentException("Value [" + stringValue + "] is out of range for a long");
            }
            // large scale -> very small number
            if (bigDecimalValue.scale() > 19) {
                if (coerce) {
                    bigIntegerValue = BigInteger.ZERO;
                } else {
                    throw new ArithmeticException("Number has a decimal part");
                }
            } else {
                bigIntegerValue = coerce ? bigDecimalValue.toBigInteger() : bigDecimalValue.toBigIntegerExact();
            }
        } catch (ArithmeticException e) {
            throw new IllegalArgumentException("Value [" + stringValue + "] has a decimal part");
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("For input string: \"" + stringValue + "\"");
        }

        if (bigIntegerValue.compareTo(LONG_MAX_VALUE_AS_BIGINTEGER) > 0 || bigIntegerValue.compareTo(LONG_MIN_VALUE_AS_BIGINTEGER) < 0) {
            throw new IllegalArgumentException("Value [" + stringValue + "] is out of range for a long");
        }

        assert bigIntegerValue.longValueExact() <= Long.MAX_VALUE; // asserting that no ArithmeticException is thrown
        return bigIntegerValue.longValue();
    }

    @Override
    public long longValue() throws IOException {
        return longValue(DEFAULT_NUMBER_COERCE_POLICY);
    }

    @Override

View on GitHub (pinned to db6a809a66)

Solutions

  1. Enable coercion on the field mapping: set "coerce": true so fractional parts are truncated toward zero.
  2. Fix the producer to emit integer values (round/truncate before sending).
  3. Change the field type to double/scaled_float if fractional precision is genuinely needed.
  4. If reading manually via the parser, call longValue(true) to allow truncation.

Example fix

// before: strict long field rejects "12.99"
PUT /idx/_mapping { "properties": { "qty": { "type": "long", "coerce": false } } }
// after: allow truncation
PUT /idx/_mapping { "properties": { "qty": { "type": "long", "coerce": true } } }
Defensive patterns

Strategy: validation

Validate before calling

static boolean isStrictLong(String s) {
  if (s == null) return false;
  try { Long.parseLong(s); return true; }
  catch (NumberFormatException e) { return false; }
}

Try / catch

try { parser.longValue(false); }
catch (IllegalArgumentException e) {
  if (e.getMessage().contains("decimal part")) { /* coerce or reject */ }
  else throw e;
}

Prevention

When it happens

Trigger: Parsing a string like "1.5", "3.14", or "0.001" into a long with coerce=false (the strict policy). Reached via longValue(false) on a VALUE_STRING token, or when a long-mapped field receives a decimal value and the index-time coerce setting is disabled.

Common situations: Mappings with "coerce": false on a long field receiving float input. Reading JSON where a numeric field is serialized with a decimal point by a producer that treats all numbers as doubles. ES|QL or runtime field evaluation casting decimal strings to long without coercion.

Related errors


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