elastic/elasticsearch · error · ClassCastException
Cannot convert [{}] to a Number
Error message
Cannot convert [{}] to a Number What it means
DefMath.getNumber throws this ClassCastException when dynamicCast (the slow runtime cast used by the def path for compound assignment and explicit casts to a numeric wrapper) receives an object that is neither a Number nor a Character. getNumber is the bridge that converts a dynamic value to Integer/Long/Double/etc. before invoking intValue()/longValue()/doubleValue(). If the object is, say, a String or a List, there is no numeric conversion and the cast cannot proceed.
Source
Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java:1228
} else if (clazz == Byte.class) {
return getNumber(value).byteValue();
} else if (clazz == Character.class) {
return (char) getNumber(value).intValue();
}
return clazz.cast(value);
} else {
return value;
}
}
/** Slowly returns a Number for o. Just for supporting dynamicCast */
static Number getNumber(Object o) {
if (o instanceof Number) {
return (Number) o;
} else if (o instanceof Character) {
return Integer.valueOf((char) o);
} else {
throw new ClassCastException("Cannot convert [" + o.getClass() + "] to a Number");
}
}
private static final MethodHandle DYNAMIC_CAST;
private static final MethodHandle DYNAMIC_RECEIVER_CAST;
static {
final MethodHandles.Lookup methodHandlesLookup = MethodHandles.lookup();
try {
DYNAMIC_CAST = methodHandlesLookup.findStatic(
methodHandlesLookup.lookupClass(),
"dynamicCast",
MethodType.methodType(Object.class, Class.class, Object.class)
);
DYNAMIC_RECEIVER_CAST = methodHandlesLookup.findStatic(
methodHandlesLookup.lookupClass(),
"dynamicReceiverCast",
MethodType.methodType(Object.class, Object.class, Object.class)
);View on GitHub (pinned to db6a809a66)
Solutions
- Validate or parse the value before the numeric cast: use Integer.parseInt or Double.parseDouble for strings, or check the field mapping.
- Avoid def for values that may be non-numeric; use explicit types so the compiler forces consistency.
- If the field can hold mixed types, add a runtime type check (instanceof Number) before the cast.
Example fix
// before def x = doc['code'].value; // keyword field, a String def total = 0; total += x; // getNumber throws // after String x = doc['code'].value; int parsed = Integer.parseInt(x); int total = 0; total += parsed;
Defensive patterns
Strategy: validation
Validate before calling
// Check the value is a Number or Character before numeric cast:
// def x = doc['code'].value;
// if (x instanceof Number || x instanceof Character) { int i = ((Number)x).intValue(); } else { /* handle */ } Type guard
// boolean isNumeric = x instanceof Number || x instanceof Character;
Prevention
- Validate def values with instanceof before numeric casts.
- Avoid compound assignment (+=) on def variables sourced from keyword/text fields.
- Parse strings with Integer.parseInt/Double.parseDouble instead of casting.
When it happens
Trigger: A def-typed compound assignment or explicit numeric cast where the RHS resolves at runtime to a non-numeric object: 'def x = 'abc'; int i = (int) x;' or 'def x = '5'; def y = 0; y += x;'. dynamicCast calls getNumber, which throws because String is not a Number or Character.
Common situations: Scripts that read def values from heterogeneous sources (JSON, doc fields of keyword/text type) and attempt arithmetic casts without validation. Compound assignments (+=, -=) on def variables where the source data is occasionally a string. Migrating scripts that worked on integer fields to keyword fields.
Related errors
- Cannot apply [>>] operation to type [float]
- Cannot apply [>>] operation to type [double]
- Cannot apply [>>] operation to type [boolean]
- Cannot apply [>>>] operation to type [float]
- Cannot apply [>>>] operation to type [double]
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/6089b70d2b9ea330.
Report an issue: GitHub.