You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[Bug] NullReferenceException in MutantPlacer.PlaceStatementControlledMutations when a constructor declares an out variable in its base(...) initializer #3810
When a constructor declares an out variable (out var x) inside its base(...) initializer, Stryker crashes with an unhandled AggregateException / NullReferenceException while injecting mutations.
The process aborts (exit code 134 on macOS), so no report is produced and the entire run is lost — even when only a single file in the solution contains the construct.
To Reproduce
A class library plus an xUnit test project. Library code (BCL only, no third-party types):
[ERR] An error occurred during the mutation test run
System.AggregateException: One or more errors occurred. (Object reference not set to an instance of an object.)
---> System.NullReferenceException: Object reference not set to an instance of an object.
at Stryker.Core.Helpers.RoslynHelper.InjectMutation[T](T sourceNode, Mutation mutation) in /_/src/Stryker.Core/Stryker.Core/Helpers/RoslynHelper.cs:line 121
at Stryker.Core.Mutants.MutationStore.<>c__DisplayClass18_0.<Inject>b__0(Mutant m) in /_/src/Stryker.Core/Stryker.Core/Mutants/MutationStore.cs:line 243
at System.Linq.Enumerable.SelectListIterator`2.MoveNext()
at System.Linq.Enumerable.Aggregate[TSource,TAccumulate](IEnumerable`1 source, TAccumulate seed, Func`3 func)
at Stryker.Core.Mutants.MutantPlacer.PlaceStatementControlledMutations(StatementSyntax original, IEnumerable`1 mutants) in /_/src/Stryker.Core/Stryker.Core/Mutants/MutantPlacer.cs:line 110
at Stryker.Core.Mutants.MutationStore.Inject(BlockSyntax mutatedNode, ExpressionSyntax originalNode, Boolean needReturn) in /_/src/Stryker.Core/Stryker.Core/Mutants/MutationStore.cs:line 242
at Stryker.Core.Mutants.MutationContext.InjectMutations(BlockSyntax mutatedNode, ExpressionSyntax originalNode, Boolean needReturn) in /_/src/Stryker.Core/Stryker.Core/Mutants/MutationContext.cs:line 196
at Stryker.Core.Mutants.CsharpNodeOrchestrators.BaseFunctionOrchestrator`1.InjectMutations(T sourceNode, T targetNode, SemanticModel semanticModel, MutationContext context) in /_/src/Stryker.Core/Stryker.Core/Mutants/CsharpNodeOrchestrators/BaseFunctionOrchestrator.cs:line 142
Followed by Unhandled exception and process abort.
Expected behavior
A construct Stryker cannot mutate should trigger the standard rollback for that node and let the run continue, rather than terminating the process and discarding the whole report. This matches the expectation stated in #3572.
Isolating the trigger
The out variable itself is fine — it is the position (inside the constructor initializer) that breaks. Both variants below were run against the same repro project:
Variant
Result
: base(int.TryParse(value, out var parsed) && parsed == 1)
crash, exit 134
: base(Parse(value) == 1) with private static int Parse(string? v) => int.TryParse(v, out var parsed) ? parsed : 0;
exit 0, 100.00 % score
Also checked, and not required to trigger it:
Reading the out variable from a later argument of the same initializer. It crashes with a single argument and no cross-argument read.
Any specific enum or third-party type — int.TryParse is enough.
Desktop
OS: macOS (Darwin 25.5.0, Apple Silicon)
.NET SDK 10.0.301, target framework net10.0
Stryker: 4.16.0 (dotnet-stryker global tool — current latest, so there is no version to upgrade to)
Test framework: xUnit
Not yet reproduced on Linux or Windows — only macOS was available to test on.
Additional context
Related but not a duplicate: Delegate with Out Result Crashes Stryker During Mutation #3572 ("Delegate with Out Result Crashes Stryker During Mutation"). That one fails in DefaultInitializationEngine.InjectOutParametersInitialization → RoslynHelper.BuildDefaultExpression; this one fails in MutantPlacer.PlaceStatementControlledMutations → RoslynHelper.InjectMutation. Same family — both surface as an NRE through BaseFunctionOrchestrator.InjectMutations, and both take the whole run down instead of rolling back — so a shared fix (defensive rollback at the orchestrator boundary) may address both.
Note for anyone hitting this: adding the file to mutate as an exclusion does not avoid the crash. Mutants are created and injected before FilePatternMutantFilter runs, so the crash happens first. The only workaround is to change the source.
--verbosity debug is useful for locating the offending file: the last Mutant N created lines before the error belong to the constructor that fails to inject.
Diagnosis, minimal repro, and trigger isolation in this report were produced with Claude Code (Opus model).
Describe the bug
When a constructor declares an out variable (
out var x) inside itsbase(...)initializer, Stryker crashes with an unhandledAggregateException/NullReferenceExceptionwhile injecting mutations.The process aborts (exit code 134 on macOS), so no report is produced and the entire run is lost — even when only a single file in the solution contains the construct.
To Reproduce
A class library plus an xUnit test project. Library code (BCL only, no third-party types):
Tests (needed only so the initial test run passes, otherwise Stryker aborts before it reaches mutation):
Run from the test project directory:
Actual behaviour
Followed by
Unhandled exceptionand process abort.Expected behavior
A construct Stryker cannot mutate should trigger the standard rollback for that node and let the run continue, rather than terminating the process and discarding the whole report. This matches the expectation stated in #3572.
Isolating the trigger
The out variable itself is fine — it is the position (inside the constructor initializer) that breaks. Both variants below were run against the same repro project:
: base(int.TryParse(value, out var parsed) && parsed == 1): base(Parse(value) == 1)withprivate static int Parse(string? v) => int.TryParse(v, out var parsed) ? parsed : 0;Also checked, and not required to trigger it:
int.TryParseis enough.Desktop
net10.0dotnet-strykerglobal tool — current latest, so there is no version to upgrade to)Not yet reproduced on Linux or Windows — only macOS was available to test on.
Additional context
DefaultInitializationEngine.InjectOutParametersInitialization→RoslynHelper.BuildDefaultExpression; this one fails inMutantPlacer.PlaceStatementControlledMutations→RoslynHelper.InjectMutation. Same family — both surface as an NRE throughBaseFunctionOrchestrator.InjectMutations, and both take the whole run down instead of rolling back — so a shared fix (defensive rollback at the orchestrator boundary) may address both.mutateas an exclusion does not avoid the crash. Mutants are created and injected beforeFilePatternMutantFilterruns, so the crash happens first. The only workaround is to change the source.--verbosity debugis useful for locating the offending file: the lastMutant N createdlines before the error belong to the constructor that fails to inject.