elastic/elasticsearch · error · IllegalArgumentException

Attempting to address a non-array type [receiverClass] as an

Error message

Attempting to address a non-array type [receiverClass] as an array.

What it means

Def.lookupArrayStore returns the array-store handle for bracket assignment x[i] = v. It handles arrays (arrayElementSetter), Maps (MAP_PUT), and Lists (LIST_SET). For any other receiverClass it throws 'Attempting to address a non-array type [...] as an array'. This is the store-side counterpart to lookupIndexNormalize/lookupArrayLoad and fires when the receiver cannot receive a bracket-store at all.

Source

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

        );
    }

    /**
     * Returns a method handle to do an array store.
     * @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 the value to set as 3rd argument. Return value is undefined and should be ignored.
     */
    static MethodHandle lookupArrayStore(Class<?> receiverClass) {
        if (receiverClass.isArray()) {
            return MethodHandles.arrayElementSetter(receiverClass);
        } else if (Map.class.isAssignableFrom(receiverClass)) {
            // maps allow access like mymap[key]
            return MAP_PUT;
        } else if (List.class.isAssignableFrom(receiverClass)) {
            return LIST_SET;
        }
        throw new IllegalArgumentException(
            "Attempting to address a non-array type " + "[" + receiverClass.getCanonicalName() + "] as an array."
        );
    }

    /**
     * Returns a method handle to do an array load.
     * @param receiverClass Class of the array to load the value from
     * @return a MethodHandle that accepts the receiver as first argument, the index as second argument.
     *   It returns the loaded value.
     */
    static MethodHandle lookupArrayLoad(Class<?> receiverClass) {
        if (receiverClass.isArray()) {
            return MethodHandles.arrayElementGetter(receiverClass);
        } else if (Map.class.isAssignableFrom(receiverClass)) {
            // maps allow access like mymap[key]
            return MAP_GET;
        } else if (List.class.isAssignableFrom(receiverClass)) {
            return LIST_GET;

View on GitHub (pinned to db6a809a66)

Solutions

  1. Confirm the receiver is a mutable array, List, or Map before bracket assignment.
  2. Use a List/Map from params or ctx for accumulation, not scalar variables.
  3. Type the receiver concretely to get compile-time validation.
  4. For source updates in update-by-query, write to ctx._source (a Map) instead of doc fields.

Example fix

// before
def n = 5;
n[0] = 1; // scalar is not array-storable
// after
def arr = new int[1];
arr[0] = 1;
Defensive patterns

Strategy: type-guard

Type guard

// Before bracket-assign on a def value, confirm it is a mutable array/List/Map
function isMutableContainer(v) {
  return Array.isArray(v) || v instanceof Map || (v && typeof v.length === 'number');
}
// if (!isMutableContainer(x)) throw new Error('Cannot store into non-container');

Try / catch

// On 'Attempting to address a non-array type', tell the author the receiver is a scalar/immutable and to use a List/Map/ctx._source.

Prevention

When it happens

Trigger: A Painless script writes x[i] = value where x is a 'def' whose runtime class is not an array, Map, or List — e.g. assigning into a String, a number, or a scalar wrapper.

Common situations: Treating a scalar as a container. Receiver resolved to an immutable type. Mistaking a wrapper for a collection. Trying to mutate doc values via bracket assignment.

Related errors


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