elastic/elasticsearch · error · ClassCastException
Cannot apply [-] operation to types [{}] and [{}].
Error message
Cannot apply [-] operation to types [{}] and [{}]. What it means
Thrown by DefMath.sub(Object, Object) when neither operand matches a supported subtraction combination. The Object overload checks instanceof Number and instanceof Character for both sides; if no branch matches (e.g., String, List, Map, or a Number paired with a non-numeric/non-character type), execution falls through to this ClassCastException. This only occurs with def-typed operands, since typed operands are resolved at compile time.
Source
Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java:497
}
}
} else if (left instanceof Character) {
if (right instanceof Number) {
if (right instanceof Double) {
return (char) left - ((Number) right).doubleValue();
} else if (right instanceof Long) {
return (char) left - ((Number) right).longValue();
} else if (right instanceof Float) {
return (char) left - ((Number) right).floatValue();
} else {
return (char) left - ((Number) right).intValue();
}
} else if (right instanceof Character) {
return (char) left - (char) right;
}
}
throw new ClassCastException(
"Cannot apply [-] operation to types "
+ "["
+ left.getClass().getCanonicalName()
+ "] and ["
+ right.getClass().getCanonicalName()
+ "]."
);
}
// eq: applicable to any arbitrary type, including nulls for both arguments!!!
private static boolean eq(int a, int b) {
return a == b;
}
private static boolean eq(long a, long b) {
return a == b;
}View on GitHub (pinned to db6a809a66)
Solutions
- Declare both operands with an explicit numeric type (int, long, float, double) so the compiler rejects incompatible types at parse time
- Add an instanceof Number guard before subtracting: if (a instanceof Number && b instanceof Number) { return ((Number)a).doubleValue() - ((Number)b).doubleValue(); }
- Fix the index mapping so the field is consistently typed as a numeric type (integer, float, etc.) across all documents
- Use doc['field'].value with a typed receiver instead of def, so the script fails early on type mismatch rather than at the subtraction site
Example fix
// before def a = doc['amount'].value; def b = doc['offset'].value; def result = a - b; // after double a = doc['amount'].value; double b = doc['offset'].value; double result = a - b;
Defensive patterns
Strategy: type-guard
Validate before calling
// Before subtraction, verify both def values are numeric
def a = params['x'];
def b = params['y'];
if (a instanceof Number && b instanceof Number) {
return ((Number) a).doubleValue() - ((Number) b).doubleValue();
} else {
return 0.0; // or throw a descriptive error
} Type guard
// Check if a def value is safe for arithmetic
boolean isNumeric(def v) {
return v instanceof Number;
} Prevention
- Avoid def for variables involved in arithmetic; use explicit numeric types (int, long, float, double)
- Verify field mappings with GET /index/_mapping before writing scripts that rely on numeric fields
- Use doc['field'].value with a typed receiver to surface type mismatches at script compile time
- Test scripts against documents with all expected field types before deploying to production
When it happens
Trigger: A Painless script subtracts two def-typed values where at least one evaluates at runtime to a non-numeric, non-character type (String, List, Map, null). The compiler emits a call to sub(Object, Object) because at least one operand is def; runtime instanceof dispatch finds no matching branch.
Common situations: Field mapped as keyword/text but script assumes numeric; heterogeneous documents where a field is sometimes numeric and sometimes string; def variable assigned from doc['field'].value where the field type varies across indices; subtracting a value parsed from a text-analyzed field.
Related errors
- Cannot apply [<] operation to types [{}] and [{}].
- Cannot apply [<=] operation to types [{}] and [{}].
- Cannot apply [>] operation to types [{}] and [{}].
- Cannot convert [{}] to an integral value.
- Cannot apply [<] operation to type [boolean]
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/78a2405719d8a237.
Report an issue: GitHub.