elastic/elasticsearch · error · IllegalArgumentException
field [{}] of type [{}] cannot be cast to a list or map
Error message
field [{}] of type [{}] cannot be cast to a list or map What it means
Thrown by ForEachProcessor.execute (sync path) when the field value is neither a Map nor a List. foreach can only iterate maps and lists; any other type (number, string, boolean, object) is rejected with the actual Java type name embedded in the message. IllegalArgumentException surfacing a schema/type mismatch between pipeline expectation and document content.
Source
Thrown at modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ForEachProcessor.java:76
}
@Override
public IngestDocument execute(IngestDocument ingestDocument) throws Exception {
assert isAsync() == false;
Object o = ingestDocument.getFieldValue(field, Object.class, ignoreMissing);
if (o == null) {
if (ignoreMissing) {
return ingestDocument;
} else {
throw new IllegalArgumentException("field [" + field + "] is null, cannot loop over its elements.");
}
} else if (o instanceof Map<?, ?> map) {
return iterateMap(ingestDocument, map);
} else if (o instanceof List<?> list) {
return iterateList(ingestDocument, list);
} else {
throw new IllegalArgumentException(
"field [" + field + "] of type [" + o.getClass().getName() + "] cannot be cast to a " + "list or map"
);
}
}
private IngestDocument iterateMap(IngestDocument document, Map<?, ?> map) throws Exception {
var newValues = Maps.newHashMapWithExpectedSize(map.size());
for (Map.Entry<?, ?> e : map.entrySet()) {
String key = (String) e.getKey();
Object previousKey = document.getIngestMetadata().put("_key", key);
Object value = e.getValue();
Object previousValue = document.getIngestMetadata().put("_value", value);
try {
processor.execute(document);
} finally {
String newKey = (String) document.getIngestMetadata().get("_key");
if (Strings.hasText(newKey)) {
newValues.put(newKey, document.getIngestMetadata().put("_value", previousValue));View on GitHub (pinned to db6a809a66)
Solutions
- Add a convert or split processor upstream to coerce the field into a list or map before foreach.
- Fix the source data to send the field as an array/object.
- Point the foreach field at the correct field path that actually holds a collection.
Example fix
// before
{"foreach": {"field": "tags", "processor": {...}}}
// after
{"split": {"field": "tags", "separator": ","}},
{"foreach": {"field": "tags", "processor": {...}}} Defensive patterns
Strategy: type-guard
Validate before calling
Object v = doc.getFieldValue(field, Object.class, true);
if (v != null && !(v instanceof Map) && !(v instanceof List)) {
throw new IllegalStateException("foreach field " + field + " is " + v.getClass().getName());
} Type guard
static boolean isIterable(Object v) {
return v == null || v instanceof Map || v instanceof List;
} Try / catch
try {
processor.execute(doc);
} catch (IllegalArgumentException e) {
if (e.getMessage().contains("cannot be cast to a list or map")) {
// coerce or route to failure store
} else throw e;
} Prevention
- Insert a convert/split processor before foreach to guarantee collection types.
- Audit document schemas periodically for fields used by foreach.
- Run pipeline simulations with diverse document shapes.
When it happens
Trigger: The configured field exists and is non-null but holds a scalar (e.g. a String or Integer) where the pipeline assumed a list/map. E.g. field "tags" is "a,b,c" string instead of ["a","b","c"].
Common situations: Source data changed shape (array became scalar), upstream convert/split processor missing, or mapping conflict where the same field is indexed as both keyword and object elsewhere.
Related errors
- could not convert value of type [{}] to transport protocol
- field [{}] is null, cannot loop over its elements.
- cannot read binary value
- cannot add non-map fields to root of document
- failure store document has unexpected structure, missing req
AI-assisted analysis of elastic/elasticsearch@db6a809a66 (2026-08-12).
Data as JSON: /api/errors/47c76376ede3a7b5.
Report an issue: GitHub.