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

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


The following commit(s) were added to refs/heads/main by this push:
     new a53ceb1417bc CAMEL-24528: camel-huggingface - surface Python inference 
errors in four task predictors
a53ceb1417bc is described below

commit a53ceb1417bc49b154bb12da7ebfbc416226243e
Author: Andrea Cosentino <[email protected]>
AuthorDate: Fri Aug 28 06:49:27 2026 +0200

    CAMEL-24528: camel-huggingface - surface Python inference errors in four 
task predictors
    
    TextGenerationPredictor, SummarizationPredictor, QuestionAnsweringPredictor 
and
    TextToImagePredictor set the returned data as the successful result without
    checking whether the Python script had returned an error payload. The six 
other
    task predictors guard the output with
    `if (result.contains("\"error\"")) throw new RuntimeCamelException(...)`, 
so a
    failed inference in these four was silently delivered as a success. For
    text-to-image the JSON error text was served as image/png bytes.
    
    Add the same guard to the four predictors. Text-to-image decodes the 
returned
    bytes to a string to check for the error marker before setting the image 
body.
    
    Co-Authored-By: Claude Opus 4.8 <[email protected]>
    Signed-off-by: Andrea Cosentino <[email protected]>
---
 .../tasks/QuestionAnsweringPredictor.java          |  4 +
 .../huggingface/tasks/SummarizationPredictor.java  |  4 +
 .../huggingface/tasks/TextGenerationPredictor.java |  4 +
 .../huggingface/tasks/TextToImagePredictor.java    |  7 ++
 .../tasks/PredictorErrorHandlingTest.java          | 97 ++++++++++++++++++++++
 5 files changed, 116 insertions(+)

diff --git 
a/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/QuestionAnsweringPredictor.java
 
b/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/QuestionAnsweringPredictor.java
index ec07bfea7202..ec66b59a5f3d 100644
--- 
a/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/QuestionAnsweringPredictor.java
+++ 
b/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/QuestionAnsweringPredictor.java
@@ -25,6 +25,7 @@ import ai.djl.modality.Output;
 import ai.djl.modality.nlp.qa.QAInput;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.apache.camel.Exchange;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.component.huggingface.HuggingFaceConstants;
 import org.apache.camel.component.huggingface.HuggingFaceEndpoint;
 
@@ -116,6 +117,9 @@ public class QuestionAnsweringPredictor extends 
AbstractTaskPredictor {
     @Override
     protected void processOutput(Exchange exchange, Output output) {
         String result = output.getAsString("data");
+        if (result.contains("\"error\"")) {
+            throw new RuntimeCamelException("Python inference failed: " + 
result);
+        }
         exchange.getMessage().setBody(result);
         exchange.getMessage().setHeader(HuggingFaceConstants.OUTPUT, result);
     }
diff --git 
a/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/SummarizationPredictor.java
 
b/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/SummarizationPredictor.java
index 09673a143721..1826a48740ce 100644
--- 
a/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/SummarizationPredictor.java
+++ 
b/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/SummarizationPredictor.java
@@ -21,6 +21,7 @@ import java.nio.charset.StandardCharsets;
 import ai.djl.modality.Input;
 import ai.djl.modality.Output;
 import org.apache.camel.Exchange;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.component.huggingface.HuggingFaceConstants;
 import org.apache.camel.component.huggingface.HuggingFaceEndpoint;
 
@@ -105,6 +106,9 @@ public class SummarizationPredictor extends 
AbstractTaskPredictor {
     @Override
     protected void processOutput(Exchange exchange, Output output) {
         String result = output.getAsString("data");
+        if (result.contains("\"error\"")) {
+            throw new RuntimeCamelException("Python inference failed: " + 
result);
+        }
         exchange.getMessage().setBody(result);
         exchange.getMessage().setHeader(HuggingFaceConstants.OUTPUT, result);
     }
diff --git 
a/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/TextGenerationPredictor.java
 
b/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/TextGenerationPredictor.java
index a33f3ccda1d9..582b70594203 100644
--- 
a/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/TextGenerationPredictor.java
+++ 
b/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/TextGenerationPredictor.java
@@ -21,6 +21,7 @@ import java.nio.charset.StandardCharsets;
 import ai.djl.modality.Input;
 import ai.djl.modality.Output;
 import org.apache.camel.Exchange;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.component.huggingface.HuggingFaceConstants;
 import org.apache.camel.component.huggingface.HuggingFaceEndpoint;
 
@@ -103,6 +104,9 @@ public class TextGenerationPredictor extends 
AbstractTaskPredictor {
     @Override
     protected void processOutput(Exchange exchange, Output output) {
         String result = output.getAsString("data");
+        if (result.contains("\"error\"")) {
+            throw new RuntimeCamelException("Python inference failed: " + 
result);
+        }
         exchange.getMessage().setBody(result);
         exchange.getMessage().setHeader(HuggingFaceConstants.OUTPUT, result);
     }
diff --git 
a/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/TextToImagePredictor.java
 
b/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/TextToImagePredictor.java
index 227c5b2e400b..a928854acd1a 100644
--- 
a/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/TextToImagePredictor.java
+++ 
b/components/camel-ai/camel-huggingface/src/main/java/org/apache/camel/component/huggingface/tasks/TextToImagePredictor.java
@@ -21,6 +21,7 @@ import java.nio.charset.StandardCharsets;
 import ai.djl.modality.Input;
 import ai.djl.modality.Output;
 import org.apache.camel.Exchange;
+import org.apache.camel.RuntimeCamelException;
 import org.apache.camel.component.huggingface.HuggingFaceEndpoint;
 
 /**
@@ -108,6 +109,12 @@ public class TextToImagePredictor extends 
AbstractTaskPredictor {
     @Override
     protected void processOutput(Exchange exchange, Output output) throws 
Exception {
         byte[] imageBytes = output.getAsBytes("data");
+        // A failed Python inference returns a JSON error payload instead of 
image bytes; surface it as
+        // an error rather than serving the error text as an image.
+        String resultJson = new String(imageBytes, StandardCharsets.UTF_8);
+        if (resultJson.contains("\"error\"")) {
+            throw new RuntimeCamelException("Python inference failed: " + 
resultJson);
+        }
         exchange.getMessage().setBody(imageBytes);
         exchange.getMessage().setHeader("Content-Type", "image/png");
     }
diff --git 
a/components/camel-ai/camel-huggingface/src/test/java/org/apache/camel/component/huggingface/tasks/PredictorErrorHandlingTest.java
 
b/components/camel-ai/camel-huggingface/src/test/java/org/apache/camel/component/huggingface/tasks/PredictorErrorHandlingTest.java
new file mode 100644
index 000000000000..eacbce07f13f
--- /dev/null
+++ 
b/components/camel-ai/camel-huggingface/src/test/java/org/apache/camel/component/huggingface/tasks/PredictorErrorHandlingTest.java
@@ -0,0 +1,97 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.camel.component.huggingface.tasks;
+
+import ai.djl.modality.Output;
+import org.apache.camel.CamelContext;
+import org.apache.camel.Exchange;
+import org.apache.camel.RuntimeCamelException;
+import org.apache.camel.component.huggingface.HuggingFaceConfiguration;
+import org.apache.camel.component.huggingface.HuggingFaceEndpoint;
+import org.apache.camel.impl.DefaultCamelContext;
+import org.apache.camel.support.DefaultExchange;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+/**
+ * Verifies that the task predictors whose Python script can return a JSON 
error payload surface it as an error instead
+ * of treating it as a successful result.
+ */
+class PredictorErrorHandlingTest {
+
+    private static final String ERROR_PAYLOAD = "{\"error\": \"model failed to 
load\"}";
+
+    private CamelContext context;
+    private HuggingFaceEndpoint endpoint;
+
+    @BeforeEach
+    void setUp() {
+        context = new DefaultCamelContext();
+        endpoint = new HuggingFaceEndpoint(null, null, new 
HuggingFaceConfiguration());
+    }
+
+    @AfterEach
+    void tearDown() {
+        context.stop();
+    }
+
+    private Output outputWith(String data) {
+        Output output = new Output();
+        output.add("data", data);
+        return output;
+    }
+
+    @Test
+    void textGenerationSurfacesInferenceError() {
+        TextGenerationPredictor predictor = new 
TextGenerationPredictor(endpoint);
+        Exchange exchange = new DefaultExchange(context);
+        assertThrows(RuntimeCamelException.class, () -> 
predictor.processOutput(exchange, outputWith(ERROR_PAYLOAD)));
+    }
+
+    @Test
+    void textGenerationPassesThroughSuccessfulResult() throws Exception {
+        TextGenerationPredictor predictor = new 
TextGenerationPredictor(endpoint);
+        Exchange exchange = new DefaultExchange(context);
+        predictor.processOutput(exchange, outputWith("a generated sentence"));
+        assertEquals("a generated sentence", 
exchange.getMessage().getBody(String.class));
+    }
+
+    @Test
+    void summarizationSurfacesInferenceError() {
+        SummarizationPredictor predictor = new 
SummarizationPredictor(endpoint);
+        Exchange exchange = new DefaultExchange(context);
+        assertThrows(RuntimeCamelException.class, () -> 
predictor.processOutput(exchange, outputWith(ERROR_PAYLOAD)));
+    }
+
+    @Test
+    void questionAnsweringSurfacesInferenceError() {
+        QuestionAnsweringPredictor predictor = new 
QuestionAnsweringPredictor(endpoint);
+        Exchange exchange = new DefaultExchange(context);
+        assertThrows(RuntimeCamelException.class, () -> 
predictor.processOutput(exchange, outputWith(ERROR_PAYLOAD)));
+    }
+
+    @Test
+    void textToImageSurfacesInferenceError() {
+        TextToImagePredictor predictor = new TextToImagePredictor(endpoint);
+        Exchange exchange = new DefaultExchange(context);
+        assertThrows(RuntimeCamelException.class, () -> 
predictor.processOutput(exchange, outputWith(ERROR_PAYLOAD)));
+    }
+}

Reply via email to