Skip to content

Commit a2d2a76

Browse files
thomhurstclaude
andauthored
fix: Add null checks for reflection calls (#1442)
Closes #1420 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.5 <[email protected]>
1 parent baa827b commit a2d2a76

File tree

2 files changed

+24
-6
lines changed

2 files changed

+24
-6
lines changed

src/ModularPipelines/Engine/ModuleExecutor.cs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -487,15 +487,25 @@ private async Task<IModuleResult> ExecuteTypedModule(
487487
var resultType = module.ResultType;
488488

489489
// Use reflection to call the generic ExecuteAsync method
490-
var executeMethod = typeof(IModuleExecutionPipeline).GetMethod(nameof(IModuleExecutionPipeline.ExecuteAsync))!
491-
.MakeGenericMethod(resultType);
490+
var executeMethodInfo = typeof(IModuleExecutionPipeline).GetMethod(nameof(IModuleExecutionPipeline.ExecuteAsync))
491+
?? throw new InvalidOperationException($"Method '{nameof(IModuleExecutionPipeline.ExecuteAsync)}' not found on type '{nameof(IModuleExecutionPipeline)}'.");
492492

493-
var task = (Task) executeMethod.Invoke(_executionPipeline, new object[] { module, executionContext, moduleContext, cancellationToken })!;
493+
var executeMethod = executeMethodInfo.MakeGenericMethod(resultType);
494+
495+
var invokeResult = executeMethod.Invoke(_executionPipeline, new object[] { module, executionContext, moduleContext, cancellationToken })
496+
?? throw new InvalidOperationException($"Invocation of '{nameof(IModuleExecutionPipeline.ExecuteAsync)}' returned null.");
497+
498+
var task = (Task)invokeResult;
494499
await task;
495500

496501
// Get the result from the completed task
497-
var resultProperty = task.GetType().GetProperty("Result")!;
498-
return (IModuleResult) resultProperty.GetValue(task)!;
502+
var resultProperty = task.GetType().GetProperty("Result")
503+
?? throw new InvalidOperationException($"Property 'Result' not found on task type '{task.GetType().Name}'.");
504+
505+
var resultValue = resultProperty.GetValue(task)
506+
?? throw new InvalidOperationException($"Property 'Result' returned null for task type '{task.GetType().Name}'.");
507+
508+
return (IModuleResult)resultValue;
499509
}
500510

501511
private async Task<IDisposable> WaitForParallelLimiter(Type moduleType)

src/ModularPipelines/Engine/OptionsProvider.cs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,15 @@ public OptionsProvider(IPipelineServiceContainerWrapper pipelineServiceContainer
3939

4040
foreach (var option in types.Select(t => _serviceProvider.GetService(typeof(IOptions<>).MakeGenericType(t))))
4141
{
42-
yield return option!.GetType().GetProperty("Value", BindingFlags.Public | BindingFlags.Instance)!.GetValue(option);
42+
if (option is null)
43+
{
44+
continue;
45+
}
46+
47+
var valueProperty = option.GetType().GetProperty("Value", BindingFlags.Public | BindingFlags.Instance)
48+
?? throw new InvalidOperationException($"Property 'Value' not found on type '{option.GetType().Name}'.");
49+
50+
yield return valueProperty.GetValue(option);
4351
}
4452
}
4553
}

0 commit comments

Comments
 (0)