{"record":{"id":"9decd79c2f20c6a9","repo":"elastic/elasticsearch","slug":"field-must-be-numeric-date-or-geopoint","errorCode":null,"errorMessage":"Field [{}] must be numeric, date, or geopoint","messagePattern":"Field \\[(.+?)\\] must be numeric, date, or geopoint","errorType":"validation","errorClass":"ParseException","httpStatus":null,"severity":"error","filePath":"modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java","lineNumber":482,"sourceCode":"                    valueSource = DateObject.getMethod(fieldData, fieldname, methodname);\n                }\n            } else {\n                // date field itself\n                if (methodname == null) {\n                    valueSource = DateField.getVariable(fieldData, fieldname, variablename);\n                } else {\n                    valueSource = DateField.getMethod(fieldData, fieldname, methodname);\n                }\n            }\n        } else if (fieldData instanceof IndexNumericFieldData) {\n            // number\n            if (methodname == null) {\n                valueSource = NumericField.getVariable(fieldData, fieldname, variablename);\n            } else {\n                valueSource = NumericField.getMethod(fieldData, fieldname, methodname);\n            }\n        } else {\n            throw new ParseException(\"Field [\" + fieldname + \"] must be numeric, date, or geopoint\", 5);\n        }\n        return valueSource;\n    }\n\n    // TODO: document and/or error if params contains _score?\n    // NOTE: by checking for the variable in params first, it allows masking document fields with a global constant,\n    // but if we were to reverse it, we could provide a way to supply dynamic defaults for documents missing the field?\n    private static void bindFromParams(@Nullable final Map<String, Object> params, final SimpleBindings bindings, final String variable)\n        throws ParseException {\n        // NOTE: by checking for the variable in vars first, it allows masking document fields with a global constant,\n        // but if we were to reverse it, we could provide a way to supply dynamic defaults for documents missing the field?\n        Object value = params.get(variable);\n        if (value instanceof Number) {\n            bindings.add(variable, DoubleValuesSource.constant(((Number) value).doubleValue()));\n        } else {\n            throw new ParseException(\"Parameter [\" + variable + \"] must be a numeric type\", 0);\n        }\n    }","sourceCodeStart":464,"sourceCodeEnd":500,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java#L464-L500","documentation":"Thrown in getDocValueSource() when the field exists in the mapping but its type is not numeric, date, or geo_point. The expression engine requires fields to be one of these types because it operates on DoubleValues; text, keyword, boolean, ip, and other types cannot provide numeric double values.","triggerScenarios":"Expression references doc['description'].value where 'description' is type text, or doc['active'].value where 'active' is type boolean. The field exists (so error 1235 doesn't fire) but the type check fails.","commonSituations":"Using an expression on a text/keyword field instead of a numeric sub-field; field type changed during reindex; assuming a field is numeric when it's actually scaled_float stored as string; geo_shape field mistaken for geo_point.","solutions":["Check the field type in the mapping: GET <index>/_mapping — confirm it is integer, long, float, double, scaled_float, date, or geo_point.","If the field is text/keyword, create a numeric sub-field or use a multi-field with a numeric type, then reindex.","For boolean fields, there is no direct expression support — use Painless or convert to numeric (0/1) at index time.","Ensure geo fields are type geo_point, not geo_shape."],"exampleFix":"// before: 'category' is a keyword field — expression cannot use it\n\"source\": \"doc['category'].value\"\n// after: use a numeric field instead\nGET my-index/_mapping  // verify which fields are numeric\n\"source\": \"doc['category_id'].value\"","handlingStrategy":"validation","validationCode":"// Verify field types are supported before using them in expressions\nGET my-index/_mapping\n// Supported types: integer, long, float, double, scaled_float, date, geo_point\n// Unsupported: text, keyword, boolean, ip, binary, object, nested, geo_shape\n// Check each doc['fieldname'] in the expression against the mapping type","typeGuard":null,"tryCatchPattern":"try {\n    engine.compile(scriptName, scriptSource, context, params);\n} catch (ScriptException e) {\n    if (e.getCause() instanceof ParseException\n        && e.getCause().getMessage().contains(\"must be numeric, date, or geopoint\")) {\n        String fieldName = extractFieldName(e.getCause().getMessage());\n        logger.error(\"Field '{}' is not numeric/date/geo_point — cannot use in expression\", fieldName);\n    }\n    throw e;\n}","preventionTips":["Confirm field types are numeric, date, or geo_point before using in expressions.","For text/keyword fields, create a numeric sub-field (multi-field) or a separate numeric field.","When reindexing or changing mappings, audit expression scripts for type compatibility.","Use the mapping validation step to catch type mismatches before runtime."],"tags":["expression","script","field-type","binding","numeric-required"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}