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

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

commit 843ab12452c01f1f9cf2993c8c598e58230dda2b
Author: Claus Ibsen <[email protected]>
AuthorDate: Sat Oct 24 20:26:36 2026 +0200

    CAMEL-26028: camel-support - the error of a failed API component call names 
its arguments, without their values (#28310)
    
    Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
    Signed-off-by: Claus Ibsen <[email protected]>
---
 .../support/component/ApiMethodHelperTest.java     | 26 +++++++++++++++++
 .../camel/support/component/ApiMethodHelper.java   | 34 ++++++++++++++++++++--
 .../ROOT/pages/camel-4x-upgrade-guide-4_18.adoc    |  7 +++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_22.adoc    |  7 +++++
 .../ROOT/pages/camel-4x-upgrade-guide-4_24.adoc    |  7 +++++
 5 files changed, 78 insertions(+), 3 deletions(-)

diff --git 
a/core/camel-core/src/test/java/org/apache/camel/support/component/ApiMethodHelperTest.java
 
b/core/camel-core/src/test/java/org/apache/camel/support/component/ApiMethodHelperTest.java
index cac6e63b9f07..2a658a78268c 100644
--- 
a/core/camel-core/src/test/java/org/apache/camel/support/component/ApiMethodHelperTest.java
+++ 
b/core/camel-core/src/test/java/org/apache/camel/support/component/ApiMethodHelperTest.java
@@ -24,6 +24,7 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 
+import org.apache.camel.RuntimeCamelException;
 import org.junit.jupiter.api.Test;
 
 import static org.apache.camel.support.component.ApiMethodArg.arg;
@@ -189,6 +190,31 @@ public class ApiMethodHelperTest {
         assertEquals("Howdy Dave", ApiMethodHelper.invokeMethod(proxy, 
TestMethod.SAYHI_1, properties), "Derived sayHi(name)");
     }
 
+    @Test
+    public void testInvokeMethodErrorShowsNoArgumentValues() {
+        // the arguments hold the endpoint options, such as a password, and 
the message data
+        TestProxy proxy = new TestProxy() {
+            @Override
+            public String sayHi(String name) {
+                throw new IllegalStateException("boom");
+            }
+        };
+        final Map<String, Object> properties = new HashMap<>();
+        properties.put("name", "Dave");
+        properties.put("password", "Secret123");
+
+        RuntimeCamelException e = assertThrows(RuntimeCamelException.class,
+                () -> ApiMethodHelper.invokeMethod(proxy, TestMethod.SAYHI_1, 
properties));
+        assertEquals("Error invoking sayHi with [name, password]: boom", 
e.getMessage());
+
+        // an argument of the wrong type fails in the invocation itself
+        properties.put("name", 42);
+        e = assertThrows(RuntimeCamelException.class,
+                () -> ApiMethodHelper.invokeMethod(proxy, TestMethod.SAYHI_1, 
properties));
+        assertTrue(e.getMessage().startsWith("Error invoking sayHi with [name, 
password]: "), e.getMessage());
+        assertFalse(e.getMessage().contains("Secret123"), e.getMessage());
+    }
+
     enum TestMethod implements ApiMethod {
 
         SAYHI(String.class, "sayHi"),
diff --git 
a/core/camel-support/src/main/java/org/apache/camel/support/component/ApiMethodHelper.java
 
b/core/camel-support/src/main/java/org/apache/camel/support/component/ApiMethodHelper.java
index 48578e162d8e..fef772a9e0b0 100644
--- 
a/core/camel-support/src/main/java/org/apache/camel/support/component/ApiMethodHelper.java
+++ 
b/core/camel-support/src/main/java/org/apache/camel/support/component/ApiMethodHelper.java
@@ -26,11 +26,14 @@ import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.TreeMap;
+import java.util.TreeSet;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.util.ObjectHelper;
+import org.apache.camel.util.SensitiveUtils;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -475,7 +478,7 @@ public final class ApiMethodHelper<T extends Enum<T> & 
ApiMethod> {
             throws RuntimeCamelException {
 
         if (LOG.isDebugEnabled()) {
-            LOG.debug("Invoking {} with arguments {}", method.getName(), 
properties);
+            LOG.debug("Invoking {} with arguments {}", method.getName(), 
masked(properties));
         }
 
         final List<String> argNames = method.getArgNames();
@@ -530,14 +533,39 @@ public final class ApiMethodHelper<T extends Enum<T> & 
ApiMethod> {
             String message = cause != null ? cause.getMessage() : 
e.getMessage();
 
             throw new RuntimeCamelException(
-                    String.format("Error invoking %s with %s: %s", 
method.getName(), properties, message),
+                    String.format("Error invoking %s with %s: %s", 
method.getName(), names(properties), message),
                     cause != null ? cause : e);
         } catch (Exception e) {
             throw new RuntimeCamelException(
-                    String.format("Error invoking %s with %s: %s", 
method.getName(), properties, e.getMessage()), e);
+                    String.format("Error invoking %s with %s: %s", 
method.getName(), names(properties), e.getMessage()), e);
         }
     }
 
+    /**
+     * The names of the arguments, for an error message: their values hold the 
endpoint options, such as a password, and
+     * the message data, which an error message must not show.
+     */
+    private static Set<String> names(Map<String, Object> properties) {
+        return new TreeSet<>(properties.keySet());
+    }
+
+    /**
+     * The arguments with the values of the sensitive options masked, such as 
a password or a token, for the debug log.
+     */
+    private static Map<String, Object> masked(Map<String, Object> properties) {
+        Map<String, Object> answer = new TreeMap<>();
+        for (Map.Entry<String, Object> entry : properties.entrySet()) {
+            Object value = entry.getValue();
+            if (SensitiveUtils.containsSensitive(entry.getKey())) {
+                value = "xxxxxx";
+            } else if (value instanceof String text) {
+                value = SensitiveUtils.maskUserInfoCredentials(text, "xxxxxx");
+            }
+            answer.put(entry.getKey(), value);
+        }
+        return answer;
+    }
+
     public enum MatchType {
         EXACT,
         SUBSET,
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc
index c73149809cd3..e345d9cdea54 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_18.adoc
@@ -443,6 +443,13 @@ hexadecimal characters, and the path of the file from the 
new `CamelGitHubFilePa
 the content of the file at that commit. Previously the body was taken as the 
commit when the header was not set, and
 the operation could not give the content of a file.
 
+=== camel-support - the error of a failed API component call names its 
arguments only
+
+When the call of an API component fails, such as one of fhir, box, 
google-drive or twilio, the error message now names
+the arguments of the call, as in `Error invoking resourceById with [password, 
resourceClass, serverUrl, stringId,
+username]: ...`, and no longer shows their values. The arguments hold the 
options of the endpoint, such as a password or
+a token, and the message data. The debug log of the call masks the values of 
the sensitive options.
+
 == Upgrading from 4.18.4 to 4.18.5
 
 === camel-azure-eventhubs
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
index ac26b12e3d84..e39078eb48c4 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_22.adoc
@@ -243,6 +243,13 @@ hexadecimal characters, and the path of the file from the 
new `CamelGitHubFilePa
 the content of the file at that commit. Previously the body was taken as the 
commit when the header was not set, and
 the operation could not give the content of a file.
 
+=== camel-support - the error of a failed API component call names its 
arguments only
+
+When the call of an API component fails, such as one of fhir, box, 
google-drive or twilio, the error message now names
+the arguments of the call, as in `Error invoking resourceById with [password, 
resourceClass, serverUrl, stringId,
+username]: ...`, and no longer shows their values. The arguments hold the 
options of the endpoint, such as a password or
+a token, and the message data. The debug log of the call masks the values of 
the sensitive options.
+
 == Upgrading from 4.22.1 to 4.22.2
 
 === camel-lra - only an LRA hosted by the configured coordinator is joined
diff --git 
a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc 
b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
index 00a397857c62..c4a87ac1fcb7 100644
--- a/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
+++ b/docs/user-manual/modules/ROOT/pages/camel-4x-upgrade-guide-4_24.adoc
@@ -3433,3 +3433,10 @@ script, now give a `byte[]` instead of a `List` of 
numbers. A script that return
 A JavaScript `Set` returned by a `quickjs` script now gives a `List`, a 
JavaScript `Map` a `Map` with its keys as text,
 and a typed array or an `ArrayBuffer` a `List` of numbers, also when nested. 
Before, a `Set` and a `Map` gave an empty
 `Map`, and a typed array a `Map` of index to value.
+
+=== camel-support - the error of a failed API component call names its 
arguments only
+
+When the call of an API component fails, such as one of fhir, box, 
google-drive or twilio, the error message now names
+the arguments of the call, as in `Error invoking resourceById with [password, 
resourceClass, serverUrl, stringId,
+username]: ...`, and no longer shows their values. The arguments hold the 
options of the endpoint, such as a password or
+a token, and the message data. The debug log of the call masks the values of 
the sensitive options.

Reply via email to