elastic/elasticsearch · error · IllegalArgumentException
Illegal list shortcut value [name].
Error message
Illegal list shortcut value [name].
What it means
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.
Source
Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java:710
if (setter != null) {
return setter;
}
// special case: maps, and lists
if (Map.class.isAssignableFrom(receiverClass)) {
// maps allow access like mymap.key
// wire 'key' as a parameter, its a constant in painless
return MethodHandles.insertArguments(MAP_PUT, 1, name);
} else if (List.class.isAssignableFrom(receiverClass)) {
// lists allow access like mylist.0
// wire '0' (index) as a parameter, its a constant. this also avoids
// parsing the same integer millions of times!
try {
int index = Integer.parseInt(name);
return MethodHandles.insertArguments(LIST_SET, 1, index);
} catch (final NumberFormatException exception) {
throw new IllegalArgumentException("Illegal list shortcut value [" + name + "].");
}
}
throw new IllegalArgumentException("dynamic setter [" + typeToCanonicalTypeName(receiverClass) + ", " + name + "] not found");
}
/**
* Returns a method handle to normalize the index into an array. This is what makes lists and arrays stored in {@code def} support
* negative offsets.
* @param receiverClass Class of the array to store the value in
* @return a MethodHandle that accepts the receiver as first argument, the index as second argument, and returns the normalized index
* to use with array loads and array stores
*/
static MethodHandle lookupIndexNormalize(Class<?> receiverClass) {
if (receiverClass.isArray()) {
return ArrayIndexNormalizeHelper.arrayIndexNormalizer(receiverClass);
} else if (Map.class.isAssignableFrom(receiverClass)) {
// noop so that mymap[key] doesn't do funny things with negative keysView on GitHub (pinned to db6a809a66)
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.
Example fix
// before def x = [1, 2, 3]; x.first = 99; // after x[0] = 99;
Defensive patterns
Strategy: type-guard
Type guard
// Guard List dot-set: only integer names
function safeListSet(list, name, value) {
if (!/^-?\d+$/.test(String(name))) throw new Error(`Use integer index for List assignment; got '${name}'`);
list[Number(name)] = value;
} Try / catch
// Surface 'Illegal list shortcut value' on the store path; advise bracket assignment.
Prevention
- Use mylist[i] = v for List assignment.
- Reserve named assignment for Maps.
- Static-type collections to catch List/Map confusion early.
When it happens
Trigger: 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.
Common situations: Confusing List and Map semantics. Expecting named-element assignment on a sequence. Runtime type being List when Map was assumed.
Related errors
- Illegal list shortcut value [{}].
- dynamic setter [receiverClass, name] not found
- dynamic method [{}, {}/{}] not found
- dynamic getter [{}, {}] not found
- Attempting to address a non-array-like type [receiverClass]
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/6aab052b17483c4c.
Report an issue: GitHub.