Browse Source

Better error message when _parent isn't an object (#21987)

If you make a mistake and specify a mapping like:
```
{
  "parent": {
    "properties": {}
  },
  "child": {
    "_parent": "parent",
    "properties": {}
  }
}
```

then the error message you get back amounts to
`Failed to parse mapping for [child]: can't cast a String to a Map`.
Since it doens't tell you *which* string can't be cast to a map you
have to dig through the stack trace to figure out what to fix. This
replaces the error message with:
```
Failed to parse mapping [child]: [_parent] must be an object containing [type]
```
so you can tell that the problem is with the `parent` field.
Nik Everett 8 years ago
parent
commit
bcef1e7452

+ 3 - 0
core/src/main/java/org/elasticsearch/index/mapper/DocumentMapperParser.java

@@ -117,6 +117,9 @@ public class DocumentMapperParser {
             MetadataFieldMapper.TypeParser typeParser = rootTypeParsers.get(fieldName);
             if (typeParser != null) {
                 iterator.remove();
+                if (false == fieldNode instanceof Map) {
+                    throw new IllegalArgumentException("[_parent] must be an object containing [type]");
+                }
                 Map<String, Object> fieldNodeMap = (Map<String, Object>) fieldNode;
                 docBuilder.put(typeParser.parse(fieldName, fieldNodeMap, parserContext));
                 fieldNodeMap.remove("type");

+ 10 - 0
core/src/test/java/org/elasticsearch/cluster/metadata/MetaDataMappingServiceTests.java

@@ -25,6 +25,7 @@ import org.elasticsearch.common.compress.CompressedXContent;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.index.IndexService;
 import org.elasticsearch.index.mapper.DocumentMapper;
+import org.elasticsearch.index.mapper.MapperParsingException;
 import org.elasticsearch.test.ESSingleNodeTestCase;
 
 import java.util.Collections;
@@ -69,6 +70,15 @@ public class MetaDataMappingServiceTests extends ESSingleNodeTestCase {
         assertThat(documentMapper.parentFieldMapper().active(), is(true));
     }
 
+    public void testParentIsAString() throws Exception {
+        // Shouldn't be able the add the _parent field pointing to an already existing type, which isn't a parent type
+        Exception e = expectThrows(MapperParsingException.class, () -> client().admin().indices().prepareCreate("test")
+                .addMapping("parent", "{\"properties\":{}}")
+                .addMapping("child", "{\"_parent\": \"parent\",\"properties\":{}}")
+                .get());
+        assertEquals("Failed to parse mapping [child]: [_parent] must be an object containing [type]", e.getMessage());
+    }
+
     public void testMappingClusterStateUpdateDoesntChangeExistingIndices() throws Exception {
         final IndexService indexService = createIndex("test", client().admin().indices().prepareCreate("test").addMapping("type"));
         final CompressedXContent currentMapping = indexService.mapperService().documentMapper("type").mappingSource();