Skip to content

Fix ClassCastException on malformed mappings in create index#22371

Open
vishdivs wants to merge 3 commits into
opensearch-project:mainfrom
vishdivs:main
Open

Fix ClassCastException on malformed mappings in create index#22371
vishdivs wants to merge 3 commits into
opensearch-project:mainfrom
vishdivs:main

Conversation

@vishdivs

@vishdivs vishdivs commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Description

Added type validation for the mappings field in CreateIndexRequest#source(). Previously, passing a non-object value (e.g., a string like "{}") for the mappings key resulted in a 500 Internal Server
Error with a ClassCastException. This change adds explicit type checks that return a proper 400 Bad Request with a clear error message.

Related Issues

Resolves #[Issue number to be closed when this PR is merged]

Check List

  • Functionality includes testing.
  • API changes companion pull request created, if applicable.
  • Public documentation issue/PR created, if applicable.

Testing

Before (500 ClassCastException):
curl -X PUT "localhost:9200/vishdivs_doc"
-H "Content-Type: application/json"
-d '{
"mappings": "{}"
}'
{"error":{"root_cause":[{"type":"class_cast_exception","reason":"class java.lang.String cannot be cast to class java.util.Map (java.lang.String and java.util.Map are in module java.base of loader
'bootstrap')"}],"type":"class_cast_exception","reason":"class java.lang.String cannot be cast to class java.util.Map (java.lang.String and java.util.Map are in module java.base of loader
'bootstrap')"},"status":500}

After (400 with clear error message):
curl -X PUT "localhost:9200/vishdivs_doc"
-H "Content-Type: application/json"
-d '{
"mappings": "{}"
}'
{"error":{"root_cause":[{"type":"parse_exception","reason":"key [mapping] must be an object"}],"type":"parse_exception","reason":"key [mapping] must be an object"},"status":400}

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check
here.


@vishdivs vishdivs requested a review from a team as a code owner July 1, 2026 14:54
Signed-off-by: Divyansh Sharma <vishdivs@amazon.com>
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

PR Reviewer Guide 🔍

(Review updated until commit 7c1adf9)

Here are some key observations to aid the review process:

🧪 PR contains tests
🔒 No security concerns identified
✅ No TODO sections
🔀 No multiple PR themes
⚡ No major issues detected

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

PR Code Suggestions ✨

Latest suggestions up to 7c1adf9

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
Possible issue
Avoid rejecting valid scalar mapping fields

The current validation of nested mapping values is too strict and will reject
legitimate mapping structures. Standard mappings like {"mappings": {"_source":
{"enabled": false}}} have object values, but mappings such as {"mappings":
{"dynamic": "strict"}} or {"mappings": {"date_detection": true}} have scalar values
at the top level and would now incorrectly throw an exception. The nested check
should only be applied where a Map is actually required, or the validation moved
into mapping() where the structure is known.

server/src/main/java/org/opensearch/action/admin/indices/create/CreateIndexRequest.java [535-538]

 if (entry.getValue() instanceof Map == false) {
     throw new OpenSearchParseException("key [mappings] must be an object");
 }
 Map<String, Object> mappings = (Map<String, Object>) entry.getValue();
-for (Map.Entry<String, Object> entry1 : mappings.entrySet()) {
-    if (entry1.getValue() instanceof Map == false) {
-        throw new OpenSearchParseException("values inside key [mappings] must be an object");
-    }
-    mapping(entry1.getKey(), (Map<String, Object>) entry1.getValue());
-}
+mapping(mappings);
Suggestion importance[1-10]: 7

__

Why: The suggestion raises a legitimate concern that the top-level mapping keys can include scalar values (like dynamic, date_detection) in some contexts, and the new nested check may reject them. However, in the typed mapping structure iterated here (type -> mapping-body), values are expected to be objects, so the strictness may still be acceptable. The improved_code also references a mapping(mappings) method that may not exist. Still, the potential regression is worth reviewing.

Medium

Previous suggestions

Suggestions up to commit 9a5ed34
CategorySuggestion                                                                                                                                    Impact
Possible issue
Avoid breaking valid mappings object shape

The new nested-value type check breaks the previously supported case where mappings
is provided directly as the properties object (e.g., {"mappings": {"properties":
{...}}}), because properties value is a Map but its children fields (like "type":
"keyword") may not be. Only reject non-Map values when treating the entry as a typed
mapping key; otherwise, pass the entire mappings map to
mapping(MapperService.SINGLE_MAPPING_NAME, mappings) as done elsewhere to preserve
backward compatibility.

server/src/main/java/org/opensearch/action/admin/indices/create/CreateIndexRequest.java [529-539]

 } else if (MAPPINGS.match(name, deprecationHandler)) {
     if (entry.getValue() instanceof Map == false) {
         throw new OpenSearchParseException("key [mappings] must be an object");
     }
     Map<String, Object> mappings = (Map<String, Object>) entry.getValue();
-    for (Map.Entry<String, Object> entry1 : mappings.entrySet()) {
-        if (entry1.getValue() instanceof Map == false) {
-            throw new OpenSearchParseException("values inside key [mappings] must be an object");
-        }
-        mapping(entry1.getKey(), (Map<String, Object>) entry1.getValue());
-    }
+    mapping(mappings);
 } else if (ALIASES.match(name, deprecationHandler)) {
Suggestion importance[1-10]: 7

__

Why: The suggestion raises a valid concern that the new nested-value check could reject valid {"mappings": {"properties": {...}}} payloads where inner field values like "type": "keyword" are strings, potentially breaking backward compatibility. However, the existing code already iterated through mappings entries treating them as typed mappings, so the behavior change may be intentional; the accuracy of the concern depends on existing usage patterns.

Medium
Suggestions up to commit 4a61a97
CategorySuggestion                                                                                                                                    Impact
General
Correct key name in error messages

The error message references key [mapping] but the actual JSON key being validated
is mappings. Using the correct key name in the error message will make debugging
easier for API users who submitted a malformed mappings field.

server/src/main/java/org/opensearch/action/admin/indices/create/CreateIndexRequest.java [529-538]

 } 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<String, Object> mappings = (Map<String, Object>) entry.getValue();
     for (Map.Entry<String, Object> 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<String, Object>) entry1.getValue());
     }
Suggestion importance[1-10]: 5

__

Why: The suggestion correctly points out that the JSON key is mappings (plural) not mapping, so the error messages could be more accurate. However, this is a minor cosmetic improvement, and changing it would also require updating the corresponding tests that assert the exact error message text.

Low
Suggestions up to commit 8ce022f
CategorySuggestion                                                                                                                                    Impact
General
Correct key name in error messages

The error messages reference [mapping] (singular), but the actual key being
validated is mappings (plural, as defined by the MAPPINGS ParseField). Update the
messages to use [mappings] for accuracy and consistency with the [settings] message
above.

server/src/main/java/org/opensearch/action/admin/indices/create/CreateIndexRequest.java [530-537]

 } 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<String, Object> mappings = (Map<String, Object>) entry.getValue();
                 for (Map.Entry<String, Object> 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<String, Object>) entry1.getValue());
                 }
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly points out that the key is mappings (plural) as defined by the MAPPINGS ParseField, so the error messages should use [mappings] for consistency with the [settings] message. This is a minor but valid correctness/consistency improvement. Note the tests would also need to be updated accordingly.

Low

Signed-off-by: Divyansh Sharma <vishdivs@amazon.com>
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 4a61a97

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 9a5ed34

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

❌ Gradle check result for 9a5ed34: FAILURE

Please examine the workflow log, locate, and copy-paste the failure(s) below, then iterate to green. Is the failure a flaky test unrelated to your change?

Signed-off-by: Divyansh Sharma <vishdivs@amazon.com>
@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Persistent review updated to latest commit 7c1adf9

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

✅ Gradle check result for 7c1adf9: SUCCESS

@codecov

codecov Bot commented Jul 1, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 73.32%. Comparing base (1e006ef) to head (7c1adf9).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@             Coverage Diff              @@
##               main   #22371      +/-   ##
============================================
- Coverage     73.40%   73.32%   -0.08%     
+ Complexity    76106    76046      -60     
============================================
  Files          6076     6076              
  Lines        345523   345527       +4     
  Branches      49737    49739       +2     
============================================
- Hits         253627   253358     -269     
- Misses        71686    71942     +256     
- Partials      20210    20227      +17     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant