This is an automated email from the ASF dual-hosted git repository.

jshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git


The following commit(s) were added to refs/heads/main by this push:
     new 1205285d4e [#10660] fix: Move model version request validation inside 
try block (#10663)
1205285d4e is described below

commit 1205285d4e035c2ceccd15dc2fc3354adb3480dd
Author: yunhwan <[email protected]>
AuthorDate: Wed Apr 8 16:35:30 2026 +0900

    [#10660] fix: Move model version request validation inside try block 
(#10663)
    
    ### What changes were proposed in this pull request?
    
    Move `request.validate()` inside the `try` block in `alterModelVersion`
    and `alterModelVersionByAlias` methods of `ModelOperations.java`, so
    that `IllegalArgumentException` from invalid requests is properly caught
    by `ExceptionHandlers.handleModelException()`.
    
    ### Why are the changes needed?
    
    `request.validate()` was called before the `try/catch` block in both
    `alterModelVersion` and `alterModelVersionByAlias`. When validation
    fails (e.g., `{"updates": null}`), the `IllegalArgumentException`
    bypasses `ExceptionHandlers.handleModelException()` and results in a 500
    Internal Server Error instead of the expected 400 Bad Request.
    
    The duplicate `request.validate()` call inside the `try` block (within
    the lambda) already exists, so removing the pre-try call is sufficient.
    
    Fix: #10660
    
    ### Does this PR introduce _any_ user-facing change?
    
    No. This fixes error response codes for invalid REST API requests from
    500 to 400.
    
    ### How was this patch tested?
    
    Added two unit tests:
    - `testAlterModelVersionWithNullUpdates`: Sends `{"updates":null}` to
    the version endpoint, asserts 400 Bad Request with
    `ILLEGAL_ARGUMENTS_CODE`
    - `testAlterModelVersionByAliasWithNullUpdates`: Sends
    `{"updates":null}` to the alias endpoint, asserts 400 Bad Request with
    `ILLEGAL_ARGUMENTS_CODE`
    
    All existing `TestModelOperations` tests continue to pass.
---
 .../gravitino/server/web/rest/ModelOperations.java | 12 +++----
 .../server/web/rest/PartitionOperations.java       | 30 ++++++++--------
 .../server/web/rest/TestModelOperations.java       | 40 ++++++++++++++++++++++
 3 files changed, 59 insertions(+), 23 deletions(-)

diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/ModelOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/ModelOperations.java
index 66b292b2cf..3c5dd63946 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/ModelOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/ModelOperations.java
@@ -180,13 +180,12 @@ public class ModelOperations {
         request.getName());
 
     try {
-      request.validate();
-      NameIdentifier modelId =
-          NameIdentifierUtil.ofModel(metalake, catalog, schema, 
request.getName());
-
       return Utils.doAs(
           httpRequest,
           () -> {
+            request.validate();
+            NameIdentifier modelId =
+                NameIdentifierUtil.ofModel(metalake, catalog, schema, 
request.getName());
             Model m =
                 modelDispatcher.registerModel(
                     modelId, request.getComment(), request.getProperties());
@@ -422,11 +421,10 @@ public class ModelOperations {
     NameIdentifier modelId = NameIdentifierUtil.ofModel(metalake, catalog, 
schema, model);
 
     try {
-      request.validate();
-
       return Utils.doAs(
           httpRequest,
           () -> {
+            request.validate();
             Map<String, String> tmpUris =
                 
Optional.ofNullable(request.getUris()).orElse(Collections.emptyMap());
             ImmutableMap.Builder<String, String> uris =
@@ -575,7 +573,6 @@ public class ModelOperations {
         schema,
         model,
         version);
-    request.validate();
 
     try {
       NameIdentifier modelId = NameIdentifierUtil.ofModel(metalake, catalog, 
schema, model);
@@ -630,7 +627,6 @@ public class ModelOperations {
         schema,
         model,
         alias);
-    request.validate();
 
     try {
       NameIdentifier modelId = NameIdentifierUtil.ofModel(metalake, catalog, 
schema, model);
diff --git 
a/server/src/main/java/org/apache/gravitino/server/web/rest/PartitionOperations.java
 
b/server/src/main/java/org/apache/gravitino/server/web/rest/PartitionOperations.java
index cc46d88bf5..85aebb6fdd 100644
--- 
a/server/src/main/java/org/apache/gravitino/server/web/rest/PartitionOperations.java
+++ 
b/server/src/main/java/org/apache/gravitino/server/web/rest/PartitionOperations.java
@@ -181,24 +181,24 @@ public class PartitionOperations {
       @PathParam("table") @AuthorizationMetadata(type = 
Entity.EntityType.TABLE) String table,
       AddPartitionsRequest request) {
     try {
-      if (request == null || request.getPartitions() == null) {
-        throw new IllegalArgumentException("partitions must not be null");
-      }
-      LOG.info(
-          "Received add {} partition(s) request for table {}.{}.{}.{} ",
-          request.getPartitions().length,
-          metalake,
-          catalog,
-          schema,
-          table);
-      Preconditions.checkArgument(
-          request.getPartitions().length == 1, "Only one partition is 
supported");
-
-      request.validate();
-
       return Utils.doAs(
           httpRequest,
           () -> {
+            if (request == null || request.getPartitions() == null) {
+              throw new IllegalArgumentException("partitions must not be 
null");
+            }
+            LOG.info(
+                "Received add {} partition(s) request for table {}.{}.{}.{} ",
+                request.getPartitions().length,
+                metalake,
+                catalog,
+                schema,
+                table);
+            Preconditions.checkArgument(
+                request.getPartitions().length == 1, "Only one partition is 
supported");
+
+            request.validate();
+
             NameIdentifier tableIdent = NameIdentifier.of(metalake, catalog, 
schema, table);
             Partition p = dispatcher.addPartition(tableIdent, 
fromDTO(request.getPartitions()[0]));
             Response response =
diff --git 
a/server/src/test/java/org/apache/gravitino/server/web/rest/TestModelOperations.java
 
b/server/src/test/java/org/apache/gravitino/server/web/rest/TestModelOperations.java
index 521096a717..12c1695768 100644
--- 
a/server/src/test/java/org/apache/gravitino/server/web/rest/TestModelOperations.java
+++ 
b/server/src/test/java/org/apache/gravitino/server/web/rest/TestModelOperations.java
@@ -1395,6 +1395,46 @@ public class TestModelOperations extends 
BaseOperationsTest {
     Assertions.assertEquals(uris, modelVersion.uris());
   }
 
+  @Test
+  void testAlterModelVersionWithNullUpdates() {
+    ModelVersionUpdatesRequest req = new ModelVersionUpdatesRequest(null);
+
+    Response resp =
+        target(modelPath())
+            .path("model1")
+            .path("versions")
+            .path("0")
+            .request(MediaType.APPLICATION_JSON_TYPE)
+            .accept("application/vnd.gravitino.v1+json")
+            .put(Entity.entity(req, MediaType.APPLICATION_JSON_TYPE));
+
+    Assertions.assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), 
resp.getStatus());
+
+    ErrorResponse errorResp = resp.readEntity(ErrorResponse.class);
+    Assertions.assertEquals(ErrorConstants.ILLEGAL_ARGUMENTS_CODE, 
errorResp.getCode());
+    Assertions.assertEquals(IllegalArgumentException.class.getSimpleName(), 
errorResp.getType());
+  }
+
+  @Test
+  void testAlterModelVersionByAliasWithNullUpdates() {
+    ModelVersionUpdatesRequest req = new ModelVersionUpdatesRequest(null);
+
+    Response resp =
+        target(modelPath())
+            .path("model1")
+            .path("aliases")
+            .path("alias1")
+            .request(MediaType.APPLICATION_JSON_TYPE)
+            .accept("application/vnd.gravitino.v1+json")
+            .put(Entity.entity(req, MediaType.APPLICATION_JSON_TYPE));
+
+    Assertions.assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), 
resp.getStatus());
+
+    ErrorResponse errorResp = resp.readEntity(ErrorResponse.class);
+    Assertions.assertEquals(ErrorConstants.ILLEGAL_ARGUMENTS_CODE, 
errorResp.getCode());
+    Assertions.assertEquals(IllegalArgumentException.class.getSimpleName(), 
errorResp.getType());
+  }
+
   @Test
   public void testGetModelVersionUri() {
     NameIdentifier modelIdent = NameIdentifierUtil.ofModel(metalake, catalog, 
schema, "model1");

Reply via email to