Skip to content

Commit b1fe79c

Browse files
thomhurstclaude
andcommitted
fix: only throw PipelineFailedException on success path
When an exception occurs during pipeline execution (e.g. ModuleFailedException), the original exception should be rethrown after OnEnd() completes. The previous implementation incorrectly threw PipelineFailedException in the catch block, replacing the original exception. This fix adds a throwOnFailure parameter to OnEnd() to distinguish: - Success path: throwOnFailure=true, may throw PipelineFailedException - Error path: throwOnFailure=false, preserves original exception Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent 5f9e96e commit b1fe79c

1 file changed

Lines changed: 6 additions & 4 deletions

File tree

src/ModularPipelines/Engine/Executors/ExecutionOrchestrator.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -119,17 +119,18 @@ private async Task<PipelineSummary> ExecuteInternal(CancellationToken cancellati
119119
{
120120
var result = await ExecutePipeline(runnableModules, organizedModules).ConfigureAwait(false);
121121

122-
return await OnEnd(organizedModules, stopWatch, start, result).ConfigureAwait(false);
122+
return await OnEnd(organizedModules, stopWatch, start, result, throwOnFailure: true).ConfigureAwait(false);
123123
}
124124
catch
125125
{
126-
await OnEnd(organizedModules, stopWatch, start, null).ConfigureAwait(false);
126+
// Don't throw PipelineFailedException here - we want to rethrow the original exception
127+
await OnEnd(organizedModules, stopWatch, start, null, throwOnFailure: false).ConfigureAwait(false);
127128
throw;
128129
}
129130
}
130131

131132
private async Task<PipelineSummary> OnEnd(OrganizedModules organizedModules, Stopwatch stopWatch, DateTimeOffset start,
132-
PipelineSummary? pipelineSummary)
133+
PipelineSummary? pipelineSummary, bool throwOnFailure)
133134
{
134135
var end = DateTimeOffset.UtcNow;
135136
pipelineSummary ??= _pipelineSummaryFactory.Create(organizedModules.AllModules, stopWatch.Elapsed, start, end);
@@ -154,7 +155,8 @@ private async Task<PipelineSummary> OnEnd(OrganizedModules organizedModules, Sto
154155
}
155156

156157
// Throw exception if pipeline failed - this ensures non-zero exit code in CI
157-
if (pipelineSummary.Status == Status.Failed && _options.Value.ThrowOnPipelineFailure)
158+
// Only throw when throwOnFailure is true (success path), not when handling an existing exception
159+
if (throwOnFailure && pipelineSummary.Status == Status.Failed && _options.Value.ThrowOnPipelineFailure)
158160
{
159161
var failedModules = pipelineSummary.GetFailedModuleResults()
160162
.Select(r => r.ModuleName)

0 commit comments

Comments
 (0)