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

dybyte pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/seatunnel.git


The following commit(s) were added to refs/heads/dev by this push:
     new 18b6cd876c [Fix][API] Preserve extension exception context in 
conditional validation (#11228)
18b6cd876c is described below

commit 18b6cd876ca23d8298c0b0926a094a67eab0f8f1
Author: zhiwei.niu <[email protected]>
AuthorDate: Wed Jul 1 16:41:58 2026 +0800

    [Fix][API] Preserve extension exception context in conditional validation 
(#11228)
---
 .../configuration/util/ConditionEvaluators.java    | 13 ++----
 .../api/configuration/util/ConfigValidator.java    | 13 +++++-
 .../configuration/util/ConfigValidatorTest.java    | 54 ++++++++++++++++++++++
 3 files changed, 69 insertions(+), 11 deletions(-)

diff --git 
a/seatunnel-api/src/main/java/org/apache/seatunnel/api/configuration/util/ConditionEvaluators.java
 
b/seatunnel-api/src/main/java/org/apache/seatunnel/api/configuration/util/ConditionEvaluators.java
index eacb9566e6..68db4568a0 100644
--- 
a/seatunnel-api/src/main/java/org/apache/seatunnel/api/configuration/util/ConditionEvaluators.java
+++ 
b/seatunnel-api/src/main/java/org/apache/seatunnel/api/configuration/util/ConditionEvaluators.java
@@ -46,15 +46,10 @@ public final class ConditionEvaluators {
             throw new OptionValidationException(
                     "Condition for option '%s' has a null operator", 
condition.getOption().key());
         }
-        try {
-            Object value = config.get(condition.getOption());
-            Evaluator evaluator = REGISTRY.get(operator);
-            return evaluator.evaluate(value, condition, config);
-        } catch (OptionValidationException e) {
-            throw new OptionValidationException(
-                    "Failed to evaluate constraint '%s' on option '%s': %s",
-                    condition.toString(), condition.getOption().key(), 
e.getRawMessage());
-        }
+
+        Object value = config.get(condition.getOption());
+        Evaluator evaluator = REGISTRY.get(operator);
+        return evaluator.evaluate(value, condition, config);
     }
 
     @SuppressWarnings({"rawtypes"})
diff --git 
a/seatunnel-api/src/main/java/org/apache/seatunnel/api/configuration/util/ConfigValidator.java
 
b/seatunnel-api/src/main/java/org/apache/seatunnel/api/configuration/util/ConfigValidator.java
index 42d1b1c7b9..ed5a2b356f 100644
--- 
a/seatunnel-api/src/main/java/org/apache/seatunnel/api/configuration/util/ConfigValidator.java
+++ 
b/seatunnel-api/src/main/java/org/apache/seatunnel/api/configuration/util/ConfigValidator.java
@@ -213,8 +213,17 @@ public class ConfigValidator {
         }
 
         for (ConditionRule conditionRule : rule.getConditionRules()) {
-            if (validate(conditionRule.getExpression())) {
-                collectErrors(conditionRule.getOptionRule(), 
conditionRule.getExpression(), errors);
+            try {
+                if (validate(conditionRule.getExpression())) {
+                    collectErrors(
+                            conditionRule.getOptionRule(), 
conditionRule.getExpression(), errors);
+                }
+            } catch (OptionValidationException e) {
+                errors.add(
+                        formatError(
+                                conditionRule.getExpression().toString(),
+                                TYPE_CONDITIONAL,
+                                e.getRawMessage()));
             }
         }
 
diff --git 
a/seatunnel-api/src/test/java/org/apache/seatunnel/api/configuration/util/ConfigValidatorTest.java
 
b/seatunnel-api/src/test/java/org/apache/seatunnel/api/configuration/util/ConfigValidatorTest.java
index a0bcd46ff1..4e1f409010 100644
--- 
a/seatunnel-api/src/test/java/org/apache/seatunnel/api/configuration/util/ConfigValidatorTest.java
+++ 
b/seatunnel-api/src/test/java/org/apache/seatunnel/api/configuration/util/ConfigValidatorTest.java
@@ -3598,4 +3598,58 @@ public class ConfigValidatorTest {
                 msg.contains("port value -1 is not positive"),
                 "extension exception message should be preserved: " + msg);
     }
+
+    @Test
+    public void testConditionalExpressionExceptionUsesWholeExpressionContext() 
{
+        ConditionExtension<Integer> throwingExtension =
+                new ConditionExtension<Integer>() {
+                    @Override
+                    public String description() {
+                        return "must be positive";
+                    }
+
+                    @Override
+                    public boolean evaluate(ReadonlyConfig config, Integer 
value)
+                            throws OptionValidationException {
+                        if (value != null && value <= 0) {
+                            throw new OptionValidationException(
+                                    "port value %d is not positive", value);
+                        }
+                        return true;
+                    }
+                };
+
+        Expression expression =
+                Expression.of(
+                        Condition.of(MODE, "stream")
+                                .and(Conditions.extension(PORT, 
throwingExtension)));
+        OptionRule rule =
+                new OptionRule(
+                        Arrays.asList(MODE, PORT),
+                        Collections.emptyList(),
+                        Collections.singletonList(
+                                new ConditionRule(
+                                        expression,
+                                        new OptionRule(
+                                                Collections.emptyList(),
+                                                Collections.emptyList(),
+                                                Collections.emptyList(),
+                                                Collections.emptyList()))),
+                        Collections.emptyList());
+
+        Map<String, Object> config = new HashMap<>();
+        config.put(MODE.key(), "stream");
+        config.put(PORT.key(), -1);
+
+        OptionValidationException ex =
+                Assertions.assertThrows(
+                        OptionValidationException.class,
+                        () -> 
ConfigValidator.of(ReadonlyConfig.fromMap(config)).validate(rule));
+        String msg = ex.getMessage();
+        Assertions.assertTrue(msg.contains("Option validation failed (1 
error):"), msg);
+        Assertions.assertTrue(
+                msg.contains("[1] option: ('mode' == stream && 'port' must be 
positive)"), msg);
+        Assertions.assertTrue(msg.contains("type: conditional"), msg);
+        Assertions.assertTrue(msg.contains("constraint: port value -1 is not 
positive"), msg);
+    }
 }

Reply via email to