From e000d8beb9d218d12d9662905aa924b196c79a85 Mon Sep 17 00:00:00 2001 From: Divyansh Sharma Date: Wed, 1 Jul 2026 20:16:54 +0530 Subject: [PATCH 1/3] Fix ClassCastException on malformed mappings in create index Signed-off-by: Divyansh Sharma --- .../indices/create/CreateIndexRequest.java | 6 ++++++ .../create/CreateIndexRequestTests.java | 18 ++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/server/src/main/java/org/opensearch/action/admin/indices/create/CreateIndexRequest.java b/server/src/main/java/org/opensearch/action/admin/indices/create/CreateIndexRequest.java index 867000111e354..08a08ffa0e591 100644 --- a/server/src/main/java/org/opensearch/action/admin/indices/create/CreateIndexRequest.java +++ b/server/src/main/java/org/opensearch/action/admin/indices/create/CreateIndexRequest.java @@ -527,8 +527,14 @@ public CreateIndexRequest source(Map source, DeprecationHandler depre } settings((Map) entry.getValue()); } else if (MAPPINGS.match(name, deprecationHandler)) { + if (entry.getValue() instanceof Map == false) { + throw new OpenSearchParseException("key [mapping] must be an object"); + } Map mappings = (Map) entry.getValue(); for (Map.Entry entry1 : mappings.entrySet()) { + if (entry1.getValue() instanceof Map == false) { + throw new OpenSearchParseException("values inside key [mapping] must be an object"); + } mapping(entry1.getKey(), (Map) entry1.getValue()); } } else if (ALIASES.match(name, deprecationHandler)) { diff --git a/server/src/test/java/org/opensearch/action/admin/indices/create/CreateIndexRequestTests.java b/server/src/test/java/org/opensearch/action/admin/indices/create/CreateIndexRequestTests.java index ee150c7b2bb71..9a3168e396f50 100644 --- a/server/src/test/java/org/opensearch/action/admin/indices/create/CreateIndexRequestTests.java +++ b/server/src/test/java/org/opensearch/action/admin/indices/create/CreateIndexRequestTests.java @@ -186,6 +186,24 @@ public void testContext() throws IOException { } } + public void testMappingsType() throws IOException { + XContentBuilder builder = MediaTypeRegistry.contentBuilder(randomFrom(XContentType.values())); + builder.startObject().startArray("mappings").endArray().endObject(); + + CreateIndexRequest parsedCreateIndexRequest = new CreateIndexRequest(); + OpenSearchParseException e = expectThrows(OpenSearchParseException.class, () -> parsedCreateIndexRequest.source(builder)); + assertThat(e.getMessage(), equalTo("key [mapping] must be an object")); + } + + public void testMappingsNestedValueType() throws IOException { + XContentBuilder builder = MediaTypeRegistry.contentBuilder(randomFrom(XContentType.values())); + builder.startObject().startObject("mappings").field("properties", "invalid_string_value").endObject().endObject(); + + CreateIndexRequest parsedCreateIndexRequest = new CreateIndexRequest(); + OpenSearchParseException e = expectThrows(OpenSearchParseException.class, () -> parsedCreateIndexRequest.source(builder)); + assertThat(e.getMessage(), equalTo("values inside key [mapping] must be an object")); + } + public static void assertMappingsEqual(Map expected, Map actual) throws IOException { assertEquals(expected.keySet(), actual.keySet()); From 4a61a972c2f6190decca9a6c3a24a33c8d72ad8a Mon Sep 17 00:00:00 2001 From: Divyansh Sharma Date: Wed, 1 Jul 2026 20:44:15 +0530 Subject: [PATCH 2/3] Adding Integ test Signed-off-by: Divyansh Sharma --- .../admin/indices/create/CreateIndexIT.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/server/src/internalClusterTest/java/org/opensearch/action/admin/indices/create/CreateIndexIT.java b/server/src/internalClusterTest/java/org/opensearch/action/admin/indices/create/CreateIndexIT.java index ab1a3dd716daa..96f0c127a36cb 100644 --- a/server/src/internalClusterTest/java/org/opensearch/action/admin/indices/create/CreateIndexIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/action/admin/indices/create/CreateIndexIT.java @@ -32,6 +32,7 @@ package org.opensearch.action.admin.indices.create; +import org.opensearch.OpenSearchParseException; import org.opensearch.action.UnavailableShardsException; import org.opensearch.action.admin.cluster.state.ClusterStateResponse; import org.opensearch.action.admin.indices.alias.Alias; @@ -56,6 +57,7 @@ import org.opensearch.common.xcontent.XContentFactory; import org.opensearch.core.action.ActionListener; import org.opensearch.core.common.bytes.BytesReference; +import org.opensearch.core.xcontent.MediaTypeRegistry; import org.opensearch.index.IndexNotFoundException; import org.opensearch.index.IndexService; import org.opensearch.index.IndexSettings; @@ -442,6 +444,24 @@ public void testCreateIndexWithNullReplicaCountPickUpClusterReplica() { } } + public void testCreateIndexWithMappingsAsString() { + CreateIndexRequest request = new CreateIndexRequest("test"); + OpenSearchParseException e = expectThrows( + OpenSearchParseException.class, + () -> request.source("{\"mappings\": \"{}\"}", MediaTypeRegistry.JSON) + ); + assertEquals("key [mapping] must be an object", e.getMessage()); + } + + public void testCreateIndexWithMappingsNestedValueAsString() { + CreateIndexRequest request = new CreateIndexRequest("test"); + OpenSearchParseException e = expectThrows( + OpenSearchParseException.class, + () -> request.source("{\"mappings\": {\"properties\": \"invalid\"}}", MediaTypeRegistry.JSON) + ); + assertEquals("values inside key [mapping] must be an object", e.getMessage()); + } + public void testCreateIndexWithContextSettingsAndTemplate() throws Exception { int numReplicas = 1; String indexName = "test-idx-1"; From 7c1adf99fbc1ff3210091f6eb04110bc0fbfbfcf Mon Sep 17 00:00:00 2001 From: Divyansh Sharma Date: Wed, 1 Jul 2026 21:02:25 +0530 Subject: [PATCH 3/3] replacing mapping with mappings Signed-off-by: Divyansh Sharma --- .../opensearch/action/admin/indices/create/CreateIndexIT.java | 4 ++-- .../action/admin/indices/create/CreateIndexRequest.java | 4 ++-- .../action/admin/indices/create/CreateIndexRequestTests.java | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/server/src/internalClusterTest/java/org/opensearch/action/admin/indices/create/CreateIndexIT.java b/server/src/internalClusterTest/java/org/opensearch/action/admin/indices/create/CreateIndexIT.java index 96f0c127a36cb..490bad90e0fe9 100644 --- a/server/src/internalClusterTest/java/org/opensearch/action/admin/indices/create/CreateIndexIT.java +++ b/server/src/internalClusterTest/java/org/opensearch/action/admin/indices/create/CreateIndexIT.java @@ -450,7 +450,7 @@ public void testCreateIndexWithMappingsAsString() { OpenSearchParseException.class, () -> request.source("{\"mappings\": \"{}\"}", MediaTypeRegistry.JSON) ); - assertEquals("key [mapping] must be an object", e.getMessage()); + assertEquals("key [mappings] must be an object", e.getMessage()); } public void testCreateIndexWithMappingsNestedValueAsString() { @@ -459,7 +459,7 @@ public void testCreateIndexWithMappingsNestedValueAsString() { OpenSearchParseException.class, () -> request.source("{\"mappings\": {\"properties\": \"invalid\"}}", MediaTypeRegistry.JSON) ); - assertEquals("values inside key [mapping] must be an object", e.getMessage()); + assertEquals("values inside key [mappings] must be an object", e.getMessage()); } public void testCreateIndexWithContextSettingsAndTemplate() throws Exception { diff --git a/server/src/main/java/org/opensearch/action/admin/indices/create/CreateIndexRequest.java b/server/src/main/java/org/opensearch/action/admin/indices/create/CreateIndexRequest.java index 08a08ffa0e591..5b29d2920cd67 100644 --- a/server/src/main/java/org/opensearch/action/admin/indices/create/CreateIndexRequest.java +++ b/server/src/main/java/org/opensearch/action/admin/indices/create/CreateIndexRequest.java @@ -528,12 +528,12 @@ public CreateIndexRequest source(Map source, DeprecationHandler depre settings((Map) entry.getValue()); } else if (MAPPINGS.match(name, deprecationHandler)) { if (entry.getValue() instanceof Map == false) { - throw new OpenSearchParseException("key [mapping] must be an object"); + throw new OpenSearchParseException("key [mappings] must be an object"); } Map mappings = (Map) entry.getValue(); for (Map.Entry entry1 : mappings.entrySet()) { if (entry1.getValue() instanceof Map == false) { - throw new OpenSearchParseException("values inside key [mapping] must be an object"); + throw new OpenSearchParseException("values inside key [mappings] must be an object"); } mapping(entry1.getKey(), (Map) entry1.getValue()); } diff --git a/server/src/test/java/org/opensearch/action/admin/indices/create/CreateIndexRequestTests.java b/server/src/test/java/org/opensearch/action/admin/indices/create/CreateIndexRequestTests.java index 9a3168e396f50..493c7ad5dd5ba 100644 --- a/server/src/test/java/org/opensearch/action/admin/indices/create/CreateIndexRequestTests.java +++ b/server/src/test/java/org/opensearch/action/admin/indices/create/CreateIndexRequestTests.java @@ -192,7 +192,7 @@ public void testMappingsType() throws IOException { CreateIndexRequest parsedCreateIndexRequest = new CreateIndexRequest(); OpenSearchParseException e = expectThrows(OpenSearchParseException.class, () -> parsedCreateIndexRequest.source(builder)); - assertThat(e.getMessage(), equalTo("key [mapping] must be an object")); + assertThat(e.getMessage(), equalTo("key [mappings] must be an object")); } public void testMappingsNestedValueType() throws IOException { @@ -201,7 +201,7 @@ public void testMappingsNestedValueType() throws IOException { CreateIndexRequest parsedCreateIndexRequest = new CreateIndexRequest(); OpenSearchParseException e = expectThrows(OpenSearchParseException.class, () -> parsedCreateIndexRequest.source(builder)); - assertThat(e.getMessage(), equalTo("values inside key [mapping] must be an object")); + assertThat(e.getMessage(), equalTo("values inside key [mappings] must be an object")); } public static void assertMappingsEqual(Map expected, Map actual) throws IOException {