{"record":{"id":"c061dd68d38dbd3c","repo":"elastic/elasticsearch","slug":"cannot-iterate-over-receiverclass","errorCode":null,"errorMessage":"Cannot iterate over [receiverClass]","messagePattern":"Cannot iterate over \\[receiverClass\\]","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java","lineNumber":1348,"sourceCode":"            MethodHandle iterator = ARRAY_TYPE_MH_MAPPING.get(arrayType);\n            return iterator != null ? iterator : OBJECT_ARRAY_MH.asType(OBJECT_ARRAY_MH.type().changeParameterType(0, arrayType));\n        }\n\n        private ArrayIteratorHelper() {}\n    }\n\n    /**\n     * Returns a method handle to do iteration (for enhanced for loop)\n     * @param receiverClass Class of the array to load the value from\n     * @return a MethodHandle that accepts the receiver as first argument, returns iterator\n     */\n    static MethodHandle lookupIterator(Class<?> receiverClass) {\n        if (Iterable.class.isAssignableFrom(receiverClass)) {\n            return OBJECT_ITERATOR;\n        } else if (receiverClass.isArray()) {\n            return ArrayIteratorHelper.newIterator(receiverClass);\n        } else {\n            throw new IllegalArgumentException(\"Cannot iterate over [\" + receiverClass.getCanonicalName() + \"]\");\n        }\n    }\n\n    // Conversion methods for def to primitive types.\n\n    public static boolean defToboolean(final Object value) {\n        if (value instanceof Boolean) {\n            return (boolean) value;\n        } else {\n            throw castException(value.getClass(), boolean.class, null);\n        }\n    }\n\n    public static byte defTobyteImplicit(final Object value) {\n        if (value instanceof Byte) {\n            return (byte) value;\n        } else {\n            throw castException(value.getClass(), byte.class, true);","sourceCodeStart":1330,"sourceCodeEnd":1366,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java#L1330-L1366","documentation":"The enhanced for loop on a def-typed variable requires the runtime type to be Iterable or an array. Def.lookupIterator checks both conditions and throws IllegalArgumentException if neither holds, because there is no way to produce an iterator from an arbitrary object.","triggerScenarios":"A Painless script iterates over a def variable whose runtime value is a scalar (Integer, String, Boolean, etc.). Example: `def x = doc['count'].value; for (def item : x) { ... }` where count resolves to an Integer.","commonSituations":"Iterating a document field that the script author assumed was an array, but the mapping stores scalar values for at least some documents. Processing search hits or aggregation buckets where a field is sometimes single-valued and sometimes absent.","solutions":["Verify the field mapping allows multiple values; if it does not, re-map or handle the scalar case separately.","Guard iteration with an instanceof check: `if (x instanceof List) { for (def item : x) { ... } }`","Wrap single values in a single-element List before iterating.","Use an explicit type declaration (List, Map) instead of def so the compiler rejects non-iterable types at compile time."],"exampleFix":"// before\ndef tags = doc['tag'].value;\nfor (def t : tags) {\n    // process tag\n}\n\n// after\ndef tags = doc['tag'].value;\nif (tags instanceof List) {\n    for (def t : tags) {\n        // process tag\n    }\n} else if (tags != null) {\n    // handle single value\n}","handlingStrategy":"type-guard","validationCode":"// Painless: verify the def value is iterable before using for-each\ndef x = doc['field'].value;\nif (x instanceof List) {\n    for (def item : x) {\n        // process item\n    }\n} else if (x != null) {\n    // handle single value\n}","typeGuard":"// Painless type guard for iterable types\ndef isIterable(def value) {\n    return value != null && (value instanceof Iterable || value.getClass().isArray());\n}","tryCatchPattern":null,"preventionTips":["Declare loop variables as List or Iterable instead of def where possible.","Check field cardinality in the mapping before iterating over document field values.","Wrap single-value access in a guard so both scalar and array cases are handled."],"tags":["painless","def-type","iteration","type-mismatch","runtime"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}