{"record":{"id":"f37ed062b4a8b2dc","repo":"elastic/elasticsearch","slug":"array-in-field-should-only-contain-strings","errorCode":null,"errorMessage":"array in field [{}] should only contain strings","messagePattern":"array in field \\[(.+?)\\] should only contain strings","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/ingest-ip-location/src/main/java/org/elasticsearch/ingest/iplocation/GeoIpProcessor.java","lineNumber":120,"sourceCode":"        }\n\n        if (ip instanceof String ipString) {\n            Map<String, Object> data = ipDataLookup.lookup(ipString);\n            if (data == null) {\n                if (ignoreMissing == false) {\n                    tag(document, type, databaseFile);\n                }\n                return document;\n            }\n            if (data.isEmpty() == false) {\n                writeGeoIpData(document, targetField, data);\n            }\n        } else if (ip instanceof List<?> ipList) {\n            boolean match = false;\n            List<Map<String, Object>> dataList = new ArrayList<>(ipList.size());\n            for (Object ipAddr : ipList) {\n                if (ipAddr instanceof String == false) {\n                    throw new IllegalArgumentException(\"array in field [\" + field + \"] should only contain strings\");\n                }\n                Map<String, Object> data = ipDataLookup.lookup((String) ipAddr);\n                if (data == null) {\n                    if (ignoreMissing == false) {\n                        tag(document, type, databaseFile);\n                    }\n                    return document;\n                }\n                if (data.isEmpty()) {\n                    dataList.add(null);\n                    continue;\n                }\n                if (firstOnly) {\n                    writeGeoIpData(document, targetField, data);\n                    return document;\n                }\n                match = true;\n                dataList.add(data);","sourceCodeStart":102,"sourceCodeEnd":138,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/ingest-ip-location/src/main/java/org/elasticsearch/ingest/iplocation/GeoIpProcessor.java#L102-L138","documentation":"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.","triggerScenarios":"The configured field is an array containing non-string elements (e.g., numbers, nested objects, booleans) mixed with or instead of IP strings.","commonSituations":"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.","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."],"exampleFix":"// before: client_ip = [\"1.2.3.4\", 12345]\n{\n  \"geoip\": { \"field\": \"client_ip\", \"target_field\": \"geo\" }\n}\n// after: sanitize upstream\n{\n  \"script\": { \"source\": \"ctx.client_ip = ctx.client_ip?.findAll { it instanceof String }\" } },\n{\n  \"geoip\": { \"field\": \"client_ip\", \"target_field\": \"geo\" }\n}","handlingStrategy":"type-guard","validationCode":"// Filter the array to strings only before geoip (via script processor)\n// ctx.client_ip = ctx.client_ip?.findAll { it instanceof String }\nList<?> list = document.getFieldValue(\"client_ip\", List.class, true);\nif (list != null && list.stream().anyMatch(e -> !(e instanceof String))) {\n    // sanitize upstream\n}","typeGuard":"boolean isStringArray(IngestDocument doc, String field) {\n    Object v = doc.getFieldValue(field, Object.class, true);\n    if (!(v instanceof List<?> l)) return false;\n    return l.stream().allMatch(e -> e == null || e instanceof String);\n}","tryCatchPattern":"try {\n    // run geoip processor on array field\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"should only contain strings\")) {\n        // add a script processor to filter non-string elements\n    } else { throw e; }\n}","preventionTips":["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."],"tags":["elasticsearch","ingest-pipeline","geoip","type-mismatch","validation"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T08:17:17.861Z"}