elastic/elasticsearch · error · IllegalArgumentException
${fullVal} cannot be converted to ${clazz.getSimpleName()} w
Error message
${fullVal} cannot be converted to ${clazz.getSimpleName()} without data loss What it means
Thrown by AbstractXContentParser.ensureNumberConversion() when coerce is false and a narrowing conversion from double to the target integer type would lose fractional data. The method compares the double value (fullVal) with the already-narrowed result; if they differ, the original value had a fractional part that would be silently truncated.
Source
Thrown at libs/x-content/src/main/java/org/elasticsearch/xcontent/support/AbstractXContentParser.java:81
this.restApiVersion = restApiVersion;
}
public AbstractXContentParser(NamedXContentRegistry xContentRegistry, DeprecationHandler deprecationHandler) {
this(xContentRegistry, deprecationHandler, RestApiVersion.current());
}
// The 3rd party parsers we rely on are known to silently truncate fractions: see
// http://fasterxml.github.io/jackson-core/javadoc/2.3.0/com/fasterxml/jackson/core/JsonParser.html#getShortValue()
// If this behaviour is flagged as undesirable and any truncation occurs
// then this method is called to trigger the"malformed" handling logic
void ensureNumberConversion(boolean coerce, long result, Class<? extends Number> clazz) throws IOException {
if (coerce == false) {
double fullVal = doDoubleValue();
if (result != fullVal) {
// Need to throw type IllegalArgumentException as current catch
// logic in NumberFieldMapper.parseCreateField relies on this
// for "malformed" value detection
throw new IllegalArgumentException(fullVal + " cannot be converted to " + clazz.getSimpleName() + " without data loss");
}
}
}
@Override
public boolean isBooleanValue() throws IOException {
return switch (currentToken()) {
case VALUE_BOOLEAN -> true;
case VALUE_STRING -> {
if (hasTextCharacters()) {
yield Booleans.isBoolean(textCharacters(), textOffset(), textLength());
} else {
yield Booleans.isBoolean(text());
}
}
default -> false;
};
}View on GitHub (pinned to db6a809a66)
Solutions
- Round or truncate the value before sending if integer storage is intended.
- Change the field mapping type from integer/long to float/double if fractional values are expected.
- Enable coerce in the mapping to accept silent truncation of fractional parts.
- Validate numeric values client-side to ensure they have no fractional component for integer fields.
Example fix
// before — fractional value into integer field with coerce=false
{ "quantity": 42.5 }
// after — integer value
{ "quantity": 42 } Defensive patterns
Strategy: validation
Validate before calling
// Before indexing into integer fields, verify no fractional part if coerce is disabled
public static void validateNoFractionalLoss(Object value, String fieldName) {
if (value instanceof Number n && n.doubleValue() != Math.floor(n.doubleValue())) {
throw new IllegalArgumentException(
fieldName + " has fractional part " + n + " that would be lost in integer conversion"
);
}
} Try / catch
try {
parser.intValue(false);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("cannot be converted to") && e.getMessage().contains("without data loss")) {
throw new BadRequestException("Fractional value cannot be stored in integer field: " + e.getMessage());
}
throw e;
} Prevention
- Ensure fractional values are only sent to float/double fields, not integer/long fields.
- Enable coerce in the mapping if silent truncation of fractional parts is acceptable.
- Round values to integers client-side before sending to integer-mapped fields.
When it happens
Trigger: A numeric field with coerce=false receiving a value like 42.5 for an integer or long field. The parser reads the value as a double internally, narrows it to long/int/short, and then detects that the double had a fractional part that was dropped. With coerce=true this truncation is allowed; with coerce=false it is rejected.
Common situations: Indexing a float/double value into an integer field mapping with coerce disabled. Client sending 3.14 where the mapping expects a long. Aggregation or script producing fractional results written to integer fields.
Related errors
- ${clazz.getSimpleName()} value passed as String
- [{}] {} doesn't support values of type: {}
- Value [${text}] is out of range for a short
- Value [${text}] is out of range for an integer
- Numeric value length [${length}] exceeds the maximum of [${M
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/98013a410a6f54ea.
Report an issue: GitHub.