shashank created CAMEL-26741:
--------------------------------

             Summary: camel-core - an Error thrown by a plain Processor escapes 
after the callback: the route continues as if it succeeded and the exchange 
stays inflight
                 Key: CAMEL-26741
                 URL: https://issues.apache.org/jira/browse/CAMEL-26741
             Project: Camel
          Issue Type: Bug
          Components: camel-core
            Reporter: shashank
            Assignee: shashank


A plain {{Processor}} is called as an {{AsyncProcessor}} through an adapter: 
{{DelegateSyncProcessor}} for {{process(...)}}, the bridge of 
{{AsyncProcessorConverterHelper}} (for example a producer that is not an 
{{AsyncProcessor}}), and the Processor adapter of the bean component 
({{AbstractBeanProcessor.useCustomAdapter}}, for a bean that is a 
{{Processor}}). Each calls the callback in {{finally}}, but catches only 
exceptions ({{DelegateSyncProcessor}} also {{LinkageError}}, the bean adapter 
also {{AssertionError}}). Any other {{Error}}, such as an {{AssertionError}} in 
a test processor or a custom {{Error}}, is thrown on after the callback was 
called:

* the exchange has no exception, so the callback continues it and the next 
steps run as if the processor had succeeded;
* the error handler, {{onException}} and {{doCatch}} never see the {{Error}};
* the {{Error}} leaves the reactive executor's loop, so work already queued 
there is left behind: the exchange stays inflight, the context stop waits its 
whole shutdown timeout, and the queued work may run later on another exchange's 
send.

{code:java}
from("direct:start")
    .onException(Error.class).handled(true).to("mock:handled").end()
    .process(e -> { throw new Error("boom"); })
    .to("mock:result");
{code}

On main, without the {{onException}}, {{template.send("direct:start", ...)}} 
throws the {{Error}} to the caller and the exchange stays inflight; with it, 
{{mock:handled}} receives nothing and {{mock:result}} receives the message. 
Stopping the context with a 5 second shutdown timeout then took 5 s.

Camel already treats an {{Error}} of a step as a failure elsewhere: the error 
handlers and {{CamelInternalProcessor}} catch {{Throwable}} when a processor 
throws before calling its callback (CAMEL-26464), 
{{DefaultErrorHandlerCatchThrowableTest}} expects a {{NoSuchMethodError}} of a 
processor to fail the exchange, CAMEL-16821 made the bean adapter fail the 
exchange on an {{AssertionError}}, and CAMEL-19497 moved its callback into 
{{finally}} so that "unhandled exceptions" do not block. CAMEL-19748 narrowed 
these catches from {{Throwable}}, as catching JVM errors can be dangerous; here 
the {{Error}} is not passed on cleanly either, as the callback was already 
called.

Seen while building the exchange sanitizer (CAMEL-26714): an {{Error}} of a 
plain {{Processor}} breaks the rule "call the callback exactly once, and do not 
throw from process" in Camel's adapter, not in the processor.

Suggested fix: the three adapters catch {{Throwable}} and set it on the 
exchange (an {{Error}} is wrapped in a {{CamelExecutionException}} by 
{{setException}}), so the exchange fails and error handling applies, as for an 
exception. This changes behaviour for an {{Error}}, so it needs an upgrade 
guide note.

_Filed with Claude Code on behalf of allthingssecurity._



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to