{"record":{"id":"f380a41edba4801f","repo":"elastic/elasticsearch","slug":"field-is-null-cannot-join","errorCode":null,"errorMessage":"field [{}] is null, cannot join.","messagePattern":"field \\[(.+?)\\] is null, cannot join\\.","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/JoinProcessor.java","lineNumber":57,"sourceCode":"    }\n\n    String getField() {\n        return field;\n    }\n\n    String getSeparator() {\n        return separator;\n    }\n\n    String getTargetField() {\n        return targetField;\n    }\n\n    @Override\n    public IngestDocument execute(IngestDocument document) {\n        List<?> list = document.getFieldValue(field, List.class);\n        if (list == null) {\n            throw new IllegalArgumentException(\"field [\" + field + \"] is null, cannot join.\");\n        }\n        String joined = list.stream().map(Object::toString).collect(Collectors.joining(separator));\n        document.setFieldValue(targetField, joined);\n        return document;\n    }\n\n    @Override\n    public String getType() {\n        return TYPE;\n    }\n\n    public static final class Factory implements Processor.Factory {\n        @Override\n        public JoinProcessor create(\n            Map<String, Processor.Factory> registry,\n            String processorTag,\n            String description,\n            Map<String, Object> config,","sourceCodeStart":39,"sourceCodeEnd":75,"githubUrl":"https://github.com/elastic/elasticsearch/blob/db6a809a667c081ca1dc7500389d26975573215f/modules/ingest-common/src/main/java/org/elasticsearch/ingest/common/JoinProcessor.java#L39-L75","documentation":"Thrown by JoinProcessor.execute when document.getFieldValue(field, List.class) returns null — the field is absent or null. Join requires a non-null list to concatenate. IllegalArgumentException; there is no ignore_missing option on this processor.","triggerScenarios":"Join processor configured on a field that does not exist or is null in the incoming document.","commonSituations":"Source data without the expected array field, upstream processor removed the field, or field path typo.","solutions":["Ensure the source field exists and is a list before join (add a set/split processor upstream).","Wrap the join processor in a conditional (\"if\": \"ctx.containsKey('tags')\") to skip documents lacking the field.","Fix the field path to match the actual document schema."],"exampleFix":"// before\n{\"join\": {\"field\": \"tags\", \"separator\": \",\"}}\n// after\n{\"join\": {\"field\": \"tags\", \"separator\": \",\", \"if\": \"ctx.tags != null\"}}","handlingStrategy":"validation","validationCode":"if (!doc.hasField(field) || doc.getFieldValue(field, List.class) == null) {\n    // skip or set field to empty list\n}","typeGuard":"static boolean canJoin(IngestDocument doc, String field) {\n    return doc.getFieldValue(field, List.class) != null;\n}","tryCatchPattern":"try {\n    joinProcessor.execute(doc);\n} catch (IllegalArgumentException e) {\n    if (e.getMessage().contains(\"is null, cannot join\")) {\n        // route to dead-letter or set default\n    } else throw e;\n}","preventionTips":["Always gate join processors with conditionals checking the field exists.","Ensure upstream produces the array field consistently.","Consider adding an upstream set processor to default the field to [] when absent."],"tags":["ingest","join","null-field","configuration"],"analyzedSha":"db6a809a667c081ca1dc7500389d26975573215f","analyzedAt":"2026-08-12T01:39:14.192Z","schemaVersion":2},"datasetVersion":"2026-08-12T06:17:24.410Z"}