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

rmetzger pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/flink-kubernetes-operator.git


The following commit(s) were added to refs/heads/main by this push:
     new 88f68e47f [FLINK-41242] Report the original exception class in 
`status.error` (#1233)
88f68e47f is described below

commit 88f68e47f2b6249aa38c7e5f0decf3cd3bdc5407
Author: Santwana Verma <[email protected]>
AuthorDate: Thu Oct 29 12:52:27 2026 +0530

    [FLINK-41242] Report the original exception class in `status.error` (#1233)
    
    * [FLINK-41242] Report the original exception class in status.error
    
    The JobManager returns a failed job's cause as a SerializedThrowable, and
    the operator took the type in status.error from the class of the throwable
    it holds, so every type read org.apache.flink.util.SerializedThrowable.
    Use the original class name that SerializedThrowable records instead. This
    applies to any SerializedThrowable in the reported error and its causes,
    most often a failed job's failure cause.
    
    Generated-by: Claude Code (Claude Opus 5.5)
    
    * [FLINK-41242] Move the SerializedThrowable class name lookup to 
ExceptionUtils
    
    Generated-by: Claude Code (Claude Opus 5.5)
    
    * [FLINK-41242] Use a static import for ExceptionUtils#getExceptionClassName
    
    Generated-by: Claude Code (Claude Opus 5.5)
    
    ---------
    
    Co-authored-by: Santwana Verma <[email protected]>
---
 .../kubernetes/operator/utils/ExceptionUtils.java  | 13 ++++++++++
 .../utils/FlinkResourceExceptionUtils.java         |  4 ++-
 .../deployment/ApplicationObserverTest.java        | 10 ++++++++
 .../operator/utils/ExceptionUtilsTest.java         | 14 ++++++++++
 .../utils/FlinkResourceExceptionUtilsTest.java     | 30 ++++++++++++++++++++++
 5 files changed, 70 insertions(+), 1 deletion(-)

diff --git 
a/flink-kubernetes-operator/src/main/java/org/apache/flink/kubernetes/operator/utils/ExceptionUtils.java
 
b/flink-kubernetes-operator/src/main/java/org/apache/flink/kubernetes/operator/utils/ExceptionUtils.java
index 002c43b79..f47db93c9 100644
--- 
a/flink-kubernetes-operator/src/main/java/org/apache/flink/kubernetes/operator/utils/ExceptionUtils.java
+++ 
b/flink-kubernetes-operator/src/main/java/org/apache/flink/kubernetes/operator/utils/ExceptionUtils.java
@@ -66,6 +66,19 @@ public class ExceptionUtils {
         return Optional.empty();
     }
 
+    /**
+     * Returns the class name of the throwable. For a {@link 
SerializedThrowable}, returns the class
+     * name of the original error it wraps.
+     *
+     * @param throwable the throwable to be processed
+     * @return the class name of the throwable, or of the original error for a 
SerializedThrowable
+     */
+    public static String getExceptionClassName(Throwable throwable) {
+        return throwable instanceof SerializedThrowable
+                ? ((SerializedThrowable) throwable).getOriginalErrorClassName()
+                : throwable.getClass().getName();
+    }
+
     /**
      * traverse the throwable and extract useful information for up to the 
first 3 possible
      * exceptions in the hierarchy.
diff --git 
a/flink-kubernetes-operator/src/main/java/org/apache/flink/kubernetes/operator/utils/FlinkResourceExceptionUtils.java
 
b/flink-kubernetes-operator/src/main/java/org/apache/flink/kubernetes/operator/utils/FlinkResourceExceptionUtils.java
index 9647ac2ae..97aaff9b0 100644
--- 
a/flink-kubernetes-operator/src/main/java/org/apache/flink/kubernetes/operator/utils/FlinkResourceExceptionUtils.java
+++ 
b/flink-kubernetes-operator/src/main/java/org/apache/flink/kubernetes/operator/utils/FlinkResourceExceptionUtils.java
@@ -37,6 +37,8 @@ import java.util.Optional;
 import java.util.regex.Pattern;
 import java.util.stream.Collectors;
 
+import static 
org.apache.flink.kubernetes.operator.utils.ExceptionUtils.getExceptionClassName;
+
 /** Flink Resource Exception utilities. */
 public final class FlinkResourceExceptionUtils {
 
@@ -122,7 +124,7 @@ public final class FlinkResourceExceptionUtils {
             Map<String, String> labelMapper) {
         FlinkResourceException flinkResourceException = 
FlinkResourceException.builder().build();
 
-        getSubstringWithMaxLength(throwable.getClass().getName(), 
lengthThreshold)
+        getSubstringWithMaxLength(getExceptionClassName(throwable), 
lengthThreshold)
                 .ifPresent(flinkResourceException::setType);
         getSubstringWithMaxLength(throwable.getMessage(), lengthThreshold)
                 .ifPresent(flinkResourceException::setMessage);
diff --git 
a/flink-kubernetes-operator/src/test/java/org/apache/flink/kubernetes/operator/observer/deployment/ApplicationObserverTest.java
 
b/flink-kubernetes-operator/src/test/java/org/apache/flink/kubernetes/operator/observer/deployment/ApplicationObserverTest.java
index 67265eaf7..433d01b96 100644
--- 
a/flink-kubernetes-operator/src/test/java/org/apache/flink/kubernetes/operator/observer/deployment/ApplicationObserverTest.java
+++ 
b/flink-kubernetes-operator/src/test/java/org/apache/flink/kubernetes/operator/observer/deployment/ApplicationObserverTest.java
@@ -35,6 +35,7 @@ import 
org.apache.flink.kubernetes.operator.api.status.TaskManagerInfo;
 import org.apache.flink.kubernetes.operator.config.FlinkConfigManager;
 import 
org.apache.flink.kubernetes.operator.config.KubernetesOperatorConfigOptions;
 import 
org.apache.flink.kubernetes.operator.exception.DeploymentFailedException;
+import org.apache.flink.kubernetes.operator.exception.FlinkResourceException;
 import org.apache.flink.kubernetes.operator.observer.TestObserverAdapter;
 import org.apache.flink.kubernetes.operator.reconciler.ReconciliationUtils;
 import org.apache.flink.kubernetes.operator.utils.EventRecorder;
@@ -42,6 +43,7 @@ import org.apache.flink.kubernetes.operator.utils.FlinkUtils;
 import org.apache.flink.kubernetes.operator.utils.SnapshotUtils;
 import org.apache.flink.runtime.client.JobStatusMessage;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
 import io.fabric8.kubernetes.api.model.Event;
 import io.fabric8.kubernetes.client.KubernetesClient;
 import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient;
@@ -62,6 +64,7 @@ import java.util.stream.Stream;
 import static 
org.apache.flink.kubernetes.operator.api.utils.FlinkResourceUtils.getCheckpointInfo;
 import static 
org.apache.flink.kubernetes.operator.api.utils.FlinkResourceUtils.getJobStatus;
 import static 
org.apache.flink.kubernetes.operator.config.KubernetesOperatorConfigOptions.OPERATOR_SAVEPOINT_FORMAT_TYPE;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNull;
@@ -270,6 +273,13 @@ public class ApplicationObserverTest extends 
OperatorTestBase {
         observer.observe(deployment, readyContext);
         Assertions.assertEquals(0, flinkService.getRunningCount());
         Assertions.assertTrue(deployment.getStatus().getError().contains("Job 
failed"));
+        assertThat(
+                        new ObjectMapper()
+                                .readValue(
+                                        deployment.getStatus().getError(),
+                                        FlinkResourceException.class)
+                                .getType())
+                .isEqualTo(RuntimeException.class.getName());
     }
 
     @Test
diff --git 
a/flink-kubernetes-operator/src/test/java/org/apache/flink/kubernetes/operator/utils/ExceptionUtilsTest.java
 
b/flink-kubernetes-operator/src/test/java/org/apache/flink/kubernetes/operator/utils/ExceptionUtilsTest.java
index 144ec3189..c48073060 100644
--- 
a/flink-kubernetes-operator/src/test/java/org/apache/flink/kubernetes/operator/utils/ExceptionUtilsTest.java
+++ 
b/flink-kubernetes-operator/src/test/java/org/apache/flink/kubernetes/operator/utils/ExceptionUtilsTest.java
@@ -63,6 +63,20 @@ public class ExceptionUtilsTest {
                 .isEqualTo(NonSerializableException.class.getName());
     }
 
+    @Test
+    void testGetExceptionClassName() {
+        assertThat(ExceptionUtils.getExceptionClassName(new 
IllegalStateException()))
+                .isEqualTo(IllegalStateException.class.getName());
+        assertThat(
+                        ExceptionUtils.getExceptionClassName(
+                                new SerializedThrowable(new 
IllegalStateException())))
+                .isEqualTo(IllegalStateException.class.getName());
+        assertThat(
+                        ExceptionUtils.getExceptionClassName(
+                                new SerializedThrowable(new 
NonSerializableException())))
+                .isEqualTo(NonSerializableException.class.getName());
+    }
+
     private static class NonSerializableException extends Exception {
 
         public NonSerializableException(String message) {
diff --git 
a/flink-kubernetes-operator/src/test/java/org/apache/flink/kubernetes/operator/utils/FlinkResourceExceptionUtilsTest.java
 
b/flink-kubernetes-operator/src/test/java/org/apache/flink/kubernetes/operator/utils/FlinkResourceExceptionUtilsTest.java
index f66f84b75..2e46b7347 100644
--- 
a/flink-kubernetes-operator/src/test/java/org/apache/flink/kubernetes/operator/utils/FlinkResourceExceptionUtilsTest.java
+++ 
b/flink-kubernetes-operator/src/test/java/org/apache/flink/kubernetes/operator/utils/FlinkResourceExceptionUtilsTest.java
@@ -30,6 +30,7 @@ import 
org.apache.flink.kubernetes.operator.exception.MissingJobManagerException
 import org.apache.flink.kubernetes.operator.exception.ReconciliationException;
 import org.apache.flink.runtime.rest.util.RestClientException;
 import org.apache.flink.util.FlinkRuntimeException;
+import org.apache.flink.util.SerializedThrowable;
 
 import 
org.apache.flink.shaded.netty4.io.netty.handler.codec.http.HttpResponseStatus;
 
@@ -49,6 +50,7 @@ import java.util.stream.Stream;
 import static 
org.apache.flink.kubernetes.operator.utils.FlinkResourceExceptionUtils.LABELS;
 import static 
org.apache.flink.kubernetes.operator.utils.FlinkResourceExceptionUtils.getSubstringWithMaxLength;
 import static 
org.apache.flink.kubernetes.operator.utils.FlinkResourceExceptionUtils.updateFlinkResourceException;
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertNull;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -282,6 +284,34 @@ public class FlinkResourceExceptionUtilsTest {
         }
     }
 
+    @Test
+    public void testSerializedThrowableReportsOriginalType() throws 
JsonProcessingException {
+        FlinkConfigManager configManager = new FlinkConfigManager(new 
Configuration());
+        SerializedThrowable serializedThrowable =
+                new SerializedThrowable(
+                        new FlinkRuntimeException(
+                                "job failed", new NumberFormatException("For 
input string: x1")));
+
+        for (AbstractFlinkResource resource : getTestResources()) {
+            updateFlinkResourceException(
+                    serializedThrowable, resource, 
configManager.getOperatorConfiguration());
+
+            FlinkResourceException flinkResourceException =
+                    new ObjectMapper()
+                            .readValue(
+                                    ((CommonStatus) 
resource.getStatus()).getError(),
+                                    FlinkResourceException.class);
+
+            assertThat(flinkResourceException.getType())
+                    .isEqualTo(FlinkRuntimeException.class.getName());
+            assertThat(flinkResourceException.getMessage())
+                    .isEqualTo(serializedThrowable.getMessage());
+            assertThat(flinkResourceException.getThrowableList())
+                    .extracting(FlinkResourceException::getType)
+                    .containsExactly(NumberFormatException.class.getName());
+        }
+    }
+
     private static ReconciliationException getTestException() {
         return new ReconciliationException(
                 "reconciliation exception message",

Reply via email to