elastic/elasticsearch · error · IllegalArgumentException

Illegal list shortcut value [{}].

Error message

Illegal list shortcut value [{}].

What it means

Def.lookupGetter handles dynamic field reads on 'def'. For a List receiver, the field name must be an integer index (lists allow mylist.0 syntax). The code Integer.parseInt(name) and throws 'Illegal list shortcut value [name]' on NumberFormatException if the name is not parseable as an integer — e.g. mylist.foo where 'foo' is non-numeric.

Source

Thrown at modules/lang-painless/src/main/java/org/elasticsearch/painless/Def.java:658

        }

        // special case: arrays, maps, and lists
        if (receiverClass.isArray() && "length".equals(name)) {
            // arrays expose .length as a read-only getter
            return arrayLengthGetter(receiverClass);
        } else 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_GET, 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_GET, 1, index);
            } catch (NumberFormatException exception) {
                throw new IllegalArgumentException("Illegal list shortcut value [" + name + "].");
            }
        }

        throw new IllegalArgumentException("dynamic getter [" + typeToCanonicalTypeName(receiverClass) + ", " + name + "] not found");
    }

    /**
     * Looks up handle for a dynamic field setter (field store)
     * <p>
     * A dynamic field store for variable {@code x} of type {@code def} looks like:
     * {@code x.field = y}
     * <p>
     * The following field stores are allowed:
     * <ul>
     *   <li>Whitelisted {@code field} from receiver's class or any superclasses.
     *   <li>Whitelisted method named {@code setField()} from receiver's class/superclasses/interfaces.
     *   <li>The value corresponding to a map key named {@code field} when the receiver is a Map.
     *   <li>The value in a list at element {@code field} (integer) when the receiver is a List.

View on GitHub (pinned to db6a809a66)

Solutions

  1. Use an integer index for List access: mylist.0 or mylist[0].
  2. If named access is intended, ensure the receiver is a Map, not a List.
  3. Bracket access (mylist[i]) is preferred for dynamic indices.

Example fix

// before
def x = [10, 20, 30];
return x.first; // non-numeric shortcut on a List
// after
return x[0];
Defensive patterns

Strategy: type-guard

Type guard

// Guard List dot-access: only allow if name is an integer string
function safeListGet(list, name) {
  if (!/^-?\d+$/.test(String(name))) throw new Error(`Use integer index for List; got '${name}'`);
  return list[Number(name)];
}

Try / catch

// Surface 'Illegal list shortcut value' to the script author with guidance to use bracket indexing.

Prevention

When it happens

Trigger: A Painless script reads a List via dot-shortcut with a non-integer name: def x = [1,2,3]; x.first or x.foo. Maps allow arbitrary string keys (mymap.key), but Lists require integer indices (mylist.0).

Common situations: Treating a List like a Map (expecting named access). Confusing list element access patterns. Runtime type of the variable being List when the author assumed Map.

Related errors


AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12). Data as JSON: /api/errors/a1a0e45614237076. Report an issue: GitHub.