elastic/elasticsearch · error · IllegalArgumentException

ordered {} are not supported

Error message

ordered {} are not supported

What it means

Thrown by the IngestGeoIpMetadata ConstructingObjectParser when the databases field is provided as an ordered array rather than as named objects. declareNamedObjects installs an order-check callback that rejects array-style input; named objects (a JSON object keyed by database id) are required. IllegalArgumentException surfaces during cluster state / API parsing of the ingest geoip metadata.

Source

Thrown at modules/ip-location/src/main/java/org/elasticsearch/ingest/geoip/IngestGeoIpMetadata.java:54

 * Holds the ingest-geoip databases that are available in the cluster state.
 */
public final class IngestGeoIpMetadata implements Metadata.ProjectCustom {

    public static final String TYPE = "ingest_geoip";
    private static final ParseField DATABASES_FIELD = new ParseField("databases");

    public static final IngestGeoIpMetadata EMPTY = new IngestGeoIpMetadata(Map.of());

    @SuppressWarnings("unchecked")
    private static final ConstructingObjectParser<IngestGeoIpMetadata, Void> PARSER = new ConstructingObjectParser<>(
        TYPE,
        a -> new IngestGeoIpMetadata(
            ((List<DatabaseConfigurationMetadata>) a[0]).stream().collect(Collectors.toMap((m) -> m.database().id(), Function.identity()))
        )
    );
    static {
        PARSER.declareNamedObjects(ConstructingObjectParser.constructorArg(), (p, c, n) -> DatabaseConfigurationMetadata.parse(p, n), v -> {
            throw new IllegalArgumentException("ordered " + DATABASES_FIELD.getPreferredName() + " are not supported");
        }, DATABASES_FIELD);
    }

    private final Map<String, DatabaseConfigurationMetadata> databases;

    public IngestGeoIpMetadata(Map<String, DatabaseConfigurationMetadata> databases) {
        this.databases = Map.copyOf(databases);
    }

    @Override
    public String getWriteableName() {
        return TYPE;
    }

    @Override
    public TransportVersion getMinimalSupportedVersion() {
        return TransportVersion.minimumCompatible();
    }

View on GitHub (pinned to db6a809a66)

Solutions

  1. Send databases as a JSON object keyed by database id, e.g. {"databases": {"mydb": {...}}} rather than [{"name":"mydb",...}].
  2. If integrating via JSON, configure the serializer to emit maps as objects and to skip null keys.
  3. Validate the request body shape against the rest-api-spec before sending.

Example fix

// before
{"databases": [{"name":"city","md5":"..."}]}
// after
{"databases": {"city": {"name":"city","md5":"..."}}}
Defensive patterns

Strategy: validation

Validate before calling

// before sending, ensure databases is a JSON object, not an array
Object databases = body.get("databases");
if (databases instanceof List) {
    throw new IllegalArgumentException("databases must be a JSON object keyed by id, not an array");
}

Prevention

When it happens

Trigger: Parsing a IngestGeoIpMetadata JSON where DATABASES_FIELD is a JSON array; declareNamedObjects' third lambda fires with the rejection message.

Common situations: Hand-crafted API request or external automation sending databases as a list; a serialization library defaulting a Map to an array; version skew where an older client sends array form.

Related errors


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