diff --git a/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java b/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java index 4802fb5a28b58..fef272d2037a6 100644 --- a/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java +++ b/server/src/main/java/org/elasticsearch/index/mapper/FieldMapper.java @@ -334,6 +334,8 @@ public final void validate(MappingLookup mappers) { } final String sourceScope = mappers.nestedLookup().getNestedParent(this.fullPath()); + ObjectMapper.Dynamic dynamic = mappers.getMapping().getRoot().dynamic; + boolean needsFieldVerification = dynamic != null && dynamic.equals(ObjectMapper.Dynamic.FALSE); for (String copyTo : this.copyTo().copyToFields()) { if (mappers.isMultiField(copyTo)) { throw new IllegalArgumentException("[copy_to] may not be used to copy to a multi-field: [" + copyTo + "]"); @@ -341,6 +343,9 @@ public final void validate(MappingLookup mappers) { if (mappers.isObjectField(copyTo)) { throw new IllegalArgumentException("Cannot copy to field [" + copyTo + "] since it is mapped as an object"); } + if (needsFieldVerification && mappers.getMapper(copyTo) == null){ + throw new IllegalArgumentException("Cannot copy to field [" + copyTo + "] since it is a non existent field"); + } final String targetScope = mappers.nestedLookup().getNestedParent(copyTo); checkNestedScopeCompatibility(sourceScope, targetScope); diff --git a/server/src/test/java/org/elasticsearch/index/mapper/CopyToMapperTests.java b/server/src/test/java/org/elasticsearch/index/mapper/CopyToMapperTests.java index 0f39a718302e0..8a4a88d074204 100644 --- a/server/src/test/java/org/elasticsearch/index/mapper/CopyToMapperTests.java +++ b/server/src/test/java/org/elasticsearch/index/mapper/CopyToMapperTests.java @@ -645,6 +645,38 @@ public void testCopyFromMultiField() { assertThat(e.getMessage(), Matchers.containsString("[copy_to] may not be used to copy from a multi-field: [field.bar]")); } + public void testCopyToNonExistentFieldDynamicFalse() { + Exception e = expectThrows(IllegalArgumentException.class, () -> createDocumentMapper(topMapping(b -> { + b.field("dynamic", "false"); + b.startObject("properties"); + { + b.startObject("test_field"); + { + b.field("type", "text"); + b.field("copy_to", "missing_field"); + } + b.endObject(); + } + b.endObject(); + }))); + assertThat(e.getMessage(), Matchers.containsString("Cannot copy to field [missing_field] since it is a non existent field")); + } + + public void testCopyToNonExistentFieldDynamicTrue() throws IOException { + DocumentMapper mapper = createDocumentMapper(topMapping(b -> { + b.field("dynamic", "true"); + b.startObject("properties"); + { + b.startObject("test_field"); + { + b.field("type", "text"); + b.field("copy_to", "missing_field"); + } + b.endObject(); + } + b.endObject();})); + } + public void testCopyToDateRangeFailure() throws Exception { DocumentMapper docMapper = createDocumentMapper(topMapping(b -> { b.startObject("properties");