elastic/elasticsearch · error · IllegalArgumentException
array in field [{}] should only contain strings
Error message
array in field [{}] should only contain strings What it means
Thrown by GeoIpProcessor.execute when the source field is a List, but one of its elements is not a String. The processor iterates list elements and requires each to be a string IP address for lookup.
Source
Thrown at modules/ingest-ip-location/src/main/java/org/elasticsearch/ingest/iplocation/GeoIpProcessor.java:120
}
if (ip instanceof String ipString) {
Map<String, Object> data = ipDataLookup.lookup(ipString);
if (data == null) {
if (ignoreMissing == false) {
tag(document, type, databaseFile);
}
return document;
}
if (data.isEmpty() == false) {
writeGeoIpData(document, targetField, data);
}
} else if (ip instanceof List<?> ipList) {
boolean match = false;
List<Map<String, Object>> dataList = new ArrayList<>(ipList.size());
for (Object ipAddr : ipList) {
if (ipAddr instanceof String == false) {
throw new IllegalArgumentException("array in field [" + field + "] should only contain strings");
}
Map<String, Object> data = ipDataLookup.lookup((String) ipAddr);
if (data == null) {
if (ignoreMissing == false) {
tag(document, type, databaseFile);
}
return document;
}
if (data.isEmpty()) {
dataList.add(null);
continue;
}
if (firstOnly) {
writeGeoIpData(document, targetField, data);
return document;
}
match = true;
dataList.add(data);View on GitHub (pinned to db6a809a66)
Solutions
- Ensure the array contains only string IP addresses by filtering upstream.
- Use a script processor to coerce or remove non-string elements before geoip.
- Split the array or map elements to a clean string-only array upstream.
Example fix
// before: client_ip = ["1.2.3.4", 12345]
{
"geoip": { "field": "client_ip", "target_field": "geo" }
}
// after: sanitize upstream
{
"script": { "source": "ctx.client_ip = ctx.client_ip?.findAll { it instanceof String }" } },
{
"geoip": { "field": "client_ip", "target_field": "geo" }
} Defensive patterns
Strategy: type-guard
Validate before calling
// Filter the array to strings only before geoip (via script processor)
// ctx.client_ip = ctx.client_ip?.findAll { it instanceof String }
List<?> list = document.getFieldValue("client_ip", List.class, true);
if (list != null && list.stream().anyMatch(e -> !(e instanceof String))) {
// sanitize upstream
} Type guard
boolean isStringArray(IngestDocument doc, String field) {
Object v = doc.getFieldValue(field, Object.class, true);
if (!(v instanceof List<?> l)) return false;
return l.stream().allMatch(e -> e == null || e instanceof String);
} Try / catch
try {
// run geoip processor on array field
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("should only contain strings")) {
// add a script processor to filter non-string elements
} else { throw e; }
} Prevention
- Filter arrays upstream to contain only string IP values.
- Add a script processor to remove non-string elements before geoip.
- Validate field schemas to ensure arrays hold only strings.
When it happens
Trigger: The configured field is an array containing non-string elements (e.g., numbers, nested objects, booleans) mixed with or instead of IP strings.
Common situations: Source data where IP arrays also include numeric IDs or metadata objects. Schema drift where the field type changed. Mixed-content arrays from uncontrolled upstream sources.
Related errors
- field [{}] should contain only string or array of strings
- field [{}] of type [{}] cannot be cast to [{}]
- field [{}] is null, cannot extract geoip information.
- failure store document has unexpected structure, missing req
- failure store document has unexpected structure, missing req
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/f37ed062b4a8b2dc.
Report an issue: GitHub.