{"record":{"id":"47c76376ede3a7b5","repo":"elastic/elasticsearch","slug":"field-of-type-cannot-be-cast-to-a-list-o","errorCode":null,"errorMessage":"field [{}] of type [{}] cannot be cast to a list or map","messagePattern":"field \\[(.+?)\\] of type \\[(.+?)\\] cannot be cast to a list or map","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ForEachProcessor.java","lineNumber":76,"sourceCode":"    }\n\n    @Override\n    public IngestDocument execute(IngestDocument ingestDocument) throws Exception {\n        assert isAsync() == false;\n\n        Object o = ingestDocument.getFieldValue(field, Object.class, ignoreMissing);\n        if (o == null) {\n            if (ignoreMissing) {\n                return ingestDocument;\n            } else {\n                throw new IllegalArgumentException(\"field [\" + field + \"] is null, cannot loop over its elements.\");\n            }\n        } else if (o instanceof Map<?, ?> map) {\n            return iterateMap(ingestDocument, map);\n        } else if (o instanceof List<?> list) {\n            return iterateList(ingestDocument, list);\n        } else {\n            throw new IllegalArgumentException(\n                \"field [\" + field + \"] of type [\" + o.getClass().getName() + \"] cannot be cast to a \" + \"list or map\"\n            );\n        }\n    }\n\n    private IngestDocument iterateMap(IngestDocument document, Map<?, ?> map) throws Exception {\n        var newValues = Maps.newHashMapWithExpectedSize(map.size());\n        for (Map.Entry<?, ?> e : map.entrySet()) {\n            String key = (String) e.getKey();\n            Object previousKey = document.getIngestMetadata().put(\"_key\", key);\n            Object value = e.getValue();\n            Object previousValue = document.getIngestMetadata().put(\"_value\", value);\n            try {\n                processor.execute(document);\n            } finally {\n                String newKey = (String) document.getIngestMetadata().get(\"_key\");\n                if (Strings.hasText(newKey)) {\n                    newValues.put(newKey, document.getIngestMetadata().put(\"_value\", previousValue));","sourceCodeStart":58,"sourceCodeEnd":94,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/ForEachProcessor.java#L58-L94","documentation":"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.","triggerScenarios":"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\"].","commonSituations":"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.","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."],"exampleFix":"// before\n{\"foreach\": {\"field\": \"tags\", \"processor\": {...}}}\n// after\n{\"split\": {\"field\": \"tags\", \"separator\": \",\"}},\n{\"foreach\": {\"field\": \"tags\", \"processor\": {...}}}","handlingStrategy":"type-guard","validationCode":"Object v = doc.getFieldValue(field, Object.class, true);\nif (v != null && !(v instanceof Map) && !(v instanceof List)) {\n    throw new IllegalStateException(\"foreach field \" + field + \" is \" + v.getClass().getName());\n}","typeGuard":"static boolean isIterable(Object v) {\n    return v == null || v instanceof Map || v instanceof List;\n}","tryCatchPattern":"try {\n    processor.execute(doc);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"cannot be cast to a list or map\")) {\n        // coerce or route to failure store\n    } else throw e;\n}","preventionTips":["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."],"tags":["ingest","foreach","type-mismatch","schema"],"backgroundTag":null,"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T13:17:24.610Z"}