{"record":{"id":"6aab052b17483c4c","repo":"elastic/elasticsearch","slug":"illegal-list-shortcut-value-name","errorCode":null,"errorMessage":"Illegal list shortcut value [name].","messagePattern":"Illegal list shortcut value \\[name\\]\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java","lineNumber":710,"sourceCode":"\n        if (setter != null) {\n            return setter;\n        }\n\n        // special case: maps, and lists\n        if (Map.class.isAssignableFrom(receiverClass)) {\n            // maps allow access like mymap.key\n            // wire 'key' as a parameter, its a constant in painless\n            return MethodHandles.insertArguments(MAP_PUT, 1, name);\n        } else if (List.class.isAssignableFrom(receiverClass)) {\n            // lists allow access like mylist.0\n            // wire '0' (index) as a parameter, its a constant. this also avoids\n            // parsing the same integer millions of times!\n            try {\n                int index = Integer.parseInt(name);\n                return MethodHandles.insertArguments(LIST_SET, 1, index);\n            } catch (final NumberFormatException exception) {\n                throw new IllegalArgumentException(\"Illegal list shortcut value [\" + name + \"].\");\n            }\n        }\n\n        throw new IllegalArgumentException(\"dynamic setter [\" + typeToCanonicalTypeName(receiverClass) + \", \" + name + \"] not found\");\n    }\n\n    /**\n     * Returns a method handle to normalize the index into an array. This is what makes lists and arrays stored in {@code def} support\n     * negative offsets.\n     * @param receiverClass Class of the array to store the value in\n     * @return a MethodHandle that accepts the receiver as first argument, the index as second argument, and returns the normalized index\n     *   to use with array loads and array stores\n     */\n    static MethodHandle lookupIndexNormalize(Class<?> receiverClass) {\n        if (receiverClass.isArray()) {\n            return ArrayIndexNormalizeHelper.arrayIndexNormalizer(receiverClass);\n        } else if (Map.class.isAssignableFrom(receiverClass)) {\n            // noop so that mymap[key] doesn't do funny things with negative keys","sourceCodeStart":692,"sourceCodeEnd":728,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java#L692-L728","documentation":"Def.lookupSetter handles dynamic field writes on 'def'. Symmetric to the getter, for a List receiver the name must be an integer index (mylist.0 = value). Integer.parseInt(name) throws NumberFormatException for non-numeric names, caught and rethrown as 'Illegal list shortcut value [name]'. This is the store (assignment) variant.","triggerScenarios":"A Painless script assigns via dot-shortcut on a List with a non-integer name: def x = [1,2,3]; x.first = 9. Maps allow mymap.key = v, but Lists require integer indices.","commonSituations":"Confusing List and Map semantics. Expecting named-element assignment on a sequence. Runtime type being List when Map was assumed.","solutions":["Use an integer index for List assignment: mylist[0] = value (bracket form preferred).","If named-key assignment is intended, ensure the receiver is a Map.","Use bracket syntax mylist[i] = v for dynamic or computed indices."],"exampleFix":"// before\ndef x = [1, 2, 3];\nx.first = 99;\n// after\nx[0] = 99;","handlingStrategy":"type-guard","validationCode":null,"typeGuard":"// Guard List dot-set: only integer names\nfunction safeListSet(list, name, value) {\n  if (!/^-?\\d+$/.test(String(name))) throw new Error(`Use integer index for List assignment; got '${name}'`);\n  list[Number(name)] = value;\n}","tryCatchPattern":"// Surface 'Illegal list shortcut value' on the store path; advise bracket assignment.","preventionTips":["Use mylist[i] = v for List assignment.","Reserve named assignment for Maps.","Static-type collections to catch List/Map confusion early."],"tags":["painless","script","dynamic-dispatch","def","list","setter","runtime"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:17:08.281Z"}