Federico Mariani created CAMEL-24138:
----------------------------------------

             Summary: camel-core - Splitter errorThreshold/maxFailedRecords: 
failure tracker leaks into nested splits and silently swallows their failures
                 Key: CAMEL-24138
                 URL: https://issues.apache.org/jira/browse/CAMEL-24138
             Project: Camel
          Issue Type: Bug
          Components: camel-core, eip
    Affects Versions: 4.22.0
            Reporter: Federico Mariani


The new {{errorThreshold}}/{{maxFailedRecords}} options (CAMEL-23264, 
unreleased 4.22.0-SNAPSHOT) store the splitter's {{SplitFailureTracker}} as a 
plain exchange property ({{CamelSplitFailureTracker}}, {{Splitter.java:210}}). 
Exchange properties are copied into every sub-exchange by 
{{createCorrelatedCopy}}, so the tracker *leaks into any nested splitter* 
running inside the outer split. The inner splitter's 
{{shouldContinueOnFailure}} looks the tracker up on _its_ input exchange:

{code:java}
SplitFailureTracker tracker = original.getProperty(SPLIT_FAILURE_TRACKER, 
SplitFailureTracker.class);
if (tracker == null) {
    return super.shouldContinueOnFailure(subExchange, original, index);   // 
normal behavior
}
tracker.recordFailure(index, subExchange.getException());
// the inner splitter has maxFailedRecords == 0 and errorThreshold == 0, so 
both checks are skipped
...
subExchange.setException(null);    // <-- inner failure silently cleared
return true;
{code}

Because the _inner_ splitter instance has no thresholds configured, both 
threshold checks are skipped and it unconditionally clears the exception of its 
own failed sub-items. Consequences:

# Inner split failures no longer propagate — the inner split (and therefore the 
outer item) *succeeds silently* even though items failed. The outer 
{{maxFailedRecords}}/{{errorThreshold}} never trips.
# Inner failures are recorded into the *outer* tracker with *inner* indexes, 
corrupting {{SplitResult}} ({{failureCount}} can exceed {{totalItems}}, making 
{{getSuccessCount()}} negative).

*Reproducer (attached, fails on main):* 
{{SplitterNestedFailureTrackerLeakIssueTest}} — outer 
{{split(body()).maxFailedRecords(1)}} around a plain inner {{split(body())}} 
whose item throws; the exchange completes without an exception instead of 
aborting:

{noformat}
org.opentest4j.AssertionFailedError: Inner split failure was silently swallowed 
by the leaked outer failure tracker ==> expected: not <null>
{noformat}

Suggested fix direction: don't discover the tracker via an inherited exchange 
property — key it per-processor instance (like the {{AGGREGATION_STRATEGY}} map 
keyed by processor), or only honor the tracker when {{this}} splitter actually 
has thresholds configured ({{errorThreshold > 0 || maxFailedRecords > 0}}).

Since CAMEL-23264 is unreleased, this can still be fixed before 4.22.0 ships.

_Filed by Claude Code on behalf of Federico Mariani (fmariani)_



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to