elastic/elasticsearch · error · ClassCastException

Cannot apply [<] operation to types [{}] and [{}].

Error message

Cannot apply [<] operation to types [{}] and [{}].

What it means

Thrown by DefMath.lt(Object, Object) when the runtime types of both operands do not match any supported less-than combination. The Object overload checks instanceof Number and instanceof Character; if neither branch matches the actual runtime types, it falls through to this ClassCastException. Only occurs with def-typed operands.

Source

Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/DefMath.java:650

                }
            }
        } 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()
                + "]."
        );
    }

    private static boolean lte(int a, int b) {
        return a <= b;
    }

    private static boolean lte(long a, long b) {
        return a <= b;
    }

    private static boolean lte(float a, float b) {

View on GitHub (pinned to db6a809a66)

Solutions

  1. Declare both operands with explicit types so the compiler catches incompatibility at parse time
  2. Guard with instanceof before comparing: if (a instanceof Number && b instanceof Number) { return ((Number)a).doubleValue() < ((Number)b).doubleValue(); }
  3. Ensure the index mapping types the field consistently as numeric across all documents and indices
  4. If comparing strings, use String.compareTo() or String.compareToIgnoreCase() instead of the < operator

Example fix

// before
def threshold = params['min'];
def value = doc['score'].value;
def passes = value < threshold;

// after
double value = doc['score'].value;
double threshold = (double) params['min'];
boolean passes = value < threshold;
Defensive patterns

Strategy: type-guard

Validate before calling

// Before comparing def values, verify types are compatible
def a = doc['field1'].value;
def b = params['threshold'];
if (a instanceof Number && b instanceof Number) {
  return ((Number) a).doubleValue() < ((Number) b).doubleValue();
} else if (a instanceof String && b instanceof String) {
  return ((String) a).compareTo((String) b) < 0;
} else {
  return false;
}

Type guard

// Type guard for def relational comparison
boolean canCompareNumerically(def a, def b) {
  return a instanceof Number && b instanceof Number;
}

Prevention

When it happens

Trigger: A Painless script applies < to two def-typed values where at least one evaluates at runtime to a non-numeric, non-character type. The compiler emits a call to lt(Object, Object); runtime instanceof dispatch finds no matching branch.

Common situations: Comparing a keyword/string field value against a number in a script; def variable holding a List or Map compared with <; field that changed type after a reindex or mapping conflict; script processing heterogeneous documents where the same field name has different types.

Related errors


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