{"record":{"id":"52c15749a6937391","repo":"elastic/elasticsearch","slug":"only-member-variables-or-member-methods-may-be-acc","errorCode":null,"errorMessage":"Only member variables or member methods may be accessed on a field when not accessing the field directly","messagePattern":"Only member variables or member methods may be accessed on a field when not accessing the field directly","errorType":"validation","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java","lineNumber":417,"sourceCode":"    private static DoubleValuesSource getDocValueSource(String variable, SearchLookup lookup) throws ParseException {\n        VariableContext[] parts = VariableContext.parse(variable);\n        if (parts[0].text.equals(\"doc\") == false) {\n            throw new ParseException(\"Unknown variable [\" + parts[0].text + \"]\", 0);\n        }\n        if (parts.length < 2 || parts[1].type != VariableContext.Type.STR_INDEX) {\n            throw new ParseException(\"Variable 'doc' must be used with a specific field like: doc['myfield']\", 3);\n        }\n\n        // .value is the default for doc['field'], its optional.\n        String variablename = \"value\";\n        String methodname = null;\n        if (parts.length == 3) {\n            if (parts[2].type == VariableContext.Type.METHOD) {\n                methodname = parts[2].text;\n            } else if (parts[2].type == VariableContext.Type.MEMBER) {\n                variablename = parts[2].text;\n            } else {\n                throw new IllegalArgumentException(\n                    \"Only member variables or member methods may be accessed on a field when not accessing the field directly\"\n                );\n            }\n        }\n        // true if the variable is of type doc['field'].date.xxx\n        boolean dateAccessor = false;\n        if (parts.length > 3) {\n            // access to the .date \"object\" within the field\n            if (parts.length == 4 && (\"date\".equals(parts[2].text) || \"getDate\".equals(parts[2].text))) {\n                if (parts[3].type == VariableContext.Type.METHOD) {\n                    methodname = parts[3].text;\n                    dateAccessor = true;\n                } else if (parts[3].type == VariableContext.Type.MEMBER) {\n                    variablename = parts[3].text;\n                    dateAccessor = true;\n                }\n            }\n            if (dateAccessor == false) {","sourceCodeStart":399,"sourceCodeEnd":435,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-expression/src/main/java/org/elasticsearch/script/expression/ExpressionScriptEngine.java#L399-L435","documentation":"Thrown in getDocValueSource() when the variable has exactly 3 parts (doc['field'].something) but the third part is neither a METHOD nor MEMBER type in the parsed VariableContext. This covers unusual parsing artifacts — e.g., a numeric index or other non-standard access pattern after the field bracket.","triggerScenarios":"An expression uses a syntax like doc['field'][0] (array indexing) or some other non-member, non-method access after the field bracket. The expression parser classifies segments as STR_INDEX, MEMBER, METHOD, or CLASS — this error fires when the third segment is STR_INDEX in an unexpected position.","commonSituations":"Attempting array-style indexing on a field; malformed expression where a bracket or parenthesis is misplaced; edge cases in VariableContext.parse producing unexpected segment types.","solutions":["Use only member access (doc['field'].value, doc['field'].lat) or method calls (doc['field'].abs()) after the field bracket.","Remove any numeric index or non-standard accessor after doc['field'].","If you need array/multi-value access, note that expression scripts only return the first value — use Painless for multi-value logic."],"exampleFix":"// before: invalid accessor type after field\n\"source\": \"doc['tags'][0]\"\n// after: use .value for the first value (expressions only support single values)\n\"source\": \"doc['tags'].value\"","handlingStrategy":"validation","validationCode":"// Validate that field accessors after doc['field'] are only .member or .method()\n// Correct: doc['field'].value, doc['field'].lat, doc['field'].abs()\n// Incorrect: doc['field'][0], doc['field']['sub']\n// Check expression source for unsupported accessor patterns","typeGuard":null,"tryCatchPattern":"try {\n    engine.compile(scriptName, scriptSource, context, params);\n} catch (ScriptException e) {\n    if (e.getCause() instanceof IllegalArgumentException\n        && e.getCause().getMessage().contains(\"Only member variables or member methods\")) {\n        logger.error(\"Use only .value or .method() after doc['field'] — no array indexing\");\n    }\n    throw e;\n}","preventionTips":["After doc['field'], use only member access (.value, .lat, .lon) or method calls (.abs(), .ln()).","Do not attempt array or index-based access on fields in expressions.","Expression scripts return only the first value for multi-valued fields — use Painless for multi-value logic.","Refer to the expression variable reference for the complete list of valid members and methods per field type."],"tags":["expression","script","syntax","field-access","variable-context"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}