## Symptom At design time, the source generator crashes with a `NullReferenceException` while generating the attribute lists of an **introduced constructor**. The null is dereferenced inside `DeclarationCollection<,>.GetEnumerator()`, reached from `ContextualSyntaxGenerator.Attribute(IAttributeData)` by way of a LINQ `Last`/`LastOrDefault` over that collection. The whole design-time pipeline execution for the project fails, so the generated source for the affected type is not produced. ## Stack trace ``` ---> System.NullReferenceException: Object reference not set to an instance of an object. Metalama.Framework.Engine.CodeModel.Collections.DeclarationCollection`2.GetEnumerator()+MoveNext() System.Linq.Enumerable.TryGetLastNonIterator[TSource](IEnumerable`1 source, Boolean& found) Metalama.Framework.Engine.SyntaxGeneration.ContextualSyntaxGenerator.Attribute(IAttributeData attribute) Metalama.Framework.Engine.SyntaxGeneration.ContextualSyntaxGenerator.AttributesForDeclaration(IFullRef`1 declaration, CompilationModel compilation, SyntaxKind attributeTargetKind) Metalama.Framework.Engine.AdviceImpl.AdviceSyntaxGenerator.GetAttributeLists(IDeclaration declaration, MemberInjectionContext context, SyntaxKind attributeTargetSyntaxKind) Metalama.Framework.Engine.AdviceImpl.Introduction.Constructors.IntroduceConstructorTransformation.GetInjectedMembers(MemberInjectionContext context) Metalama.Framework.Engine.Pipeline.DesignTime.DesignTimeSyntaxTreeGenerator.<>c__DisplayClass0_0.<GenerateDesignTimeSyntaxTreesAsync>g__ProcessTransformationsOnType|6(INamedType declaringTypeOrExtensionBlock, IEnumerable`1 typeTransformations) Metalama.Framework.Engine.Pipeline.DesignTime.DesignTimeSyntaxTreeGenerator.<>c__DisplayClass0_0.<GenerateDesignTimeSyntaxTreesAsync>g__ProcessTransformationsOnTypeOrNamespace|4(KeyValuePair`2 transformationGroup) Metalama.Framework.Engine.Utilities.Threading.ConcurrentTaskRunner.<>c__DisplayClass1_0`1.<RunConcurrentlyAsync>g__ProcessQueue|0() System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state) System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread) Metalama.Framework.Engine.Pipeline.DesignTime.DesignTimeSyntaxTreeGenerator.GenerateDesignTimeSyntaxTreesAsync(ProjectServiceProvider serviceProvider, PartialCompilation partialCompilation, CompilationModel initialCompilationModel, CompilationModel finalCompilationModel, IEnumerable`1 transformations, UserDiagnosticSink diagnostics, TestableCancellationToken cancellationToken) Metalama.Framework.Engine.Pipeline.DesignTime.DesignTimePipelineStage.GetStageResultAsync(AspectPipelineConfiguration pipelineConfiguration, AspectPipelineResult input, PipelineStepsResult pipelineStepsResult, TestableCancellationToken cancellationToken) Metalama.Framework.Engine.Pipeline.HighLevelPipelineStage.ExecuteAsync(AspectPipelineConfiguration pipelineConfiguration, AspectPipelineResult input, IDiagnosticAdder diagnostics, TestableCancellationToken cancellationToken) Metalama.Framework.Engine.Pipeline.AspectPipeline.ExecuteAsync(PartialCompilation compilation, IDiagnosticAdder diagnosticAdder, AspectPipelineConfiguration pipelineConfiguration, TestableCancellationToken cancellationToken) Metalama.Framework.DesignTime.Pipeline.DesignTimeAspectPipeline.PipelineState.ExecuteAsync(PipelineState state, PartialCompilation compilation, DesignTimeProjectVersion projectVersion, TestableCancellationToken cancellationToken) Metalama.Framework.DesignTime.Pipeline.DesignTimeAspectPipeline.ExecutePartialAsync(PartialCompilation partialCompilation, DesignTimeProjectVersion projectVersion, AsyncExecutionContext executionContext, TestableCancellationToken cancellationToken) Metalama.Framework.DesignTime.Pipeline.DesignTimeAspectPipeline.ExecuteAsync(Compilation compilation, Boolean autoResumePipeline, AsyncExecutionContext executionContext, TestableCancellationToken cancellationToken) Metalama.Framework.DesignTime.Pipeline.DesignTimeAspectPipeline.ExecuteAsync(Compilation compilation, Boolean autoResumePipeline, AsyncExecutionContext executionContext, TestableCancellationToken cancellationToken) Metalama.Framework.DesignTime.SourceGeneration.AnalysisProcessProjectSourceGenerator.ComputeAsync(Compilation compilation, TestableCancellationToken cancellationToken) Metalama.Framework.DesignTime.SourceGeneration.AnalysisProcessProjectSourceGenerator.ComputeAndPublishAsync(Compilation compilation, TestableCancellationToken cancellationToken) Metalama.Framework.DesignTime.Utilities.TaskBag.<>c__DisplayClass5_0.<<Enqueue>b__0>d.MoveNext() ``` The exception message is the stock BCL string, so it carries no further information. ## Scale, and it is small **1 distinct installation, 1 report, 1 crash signature**, over the retained window, which is 90 days. Every figure is from `measure` over the single problem this issue covers, not from a lead problem in a larger group. **This is not an argument for a maintainer's afternoon and the report does not pretend otherwise.** The reasons it is filed anyway are the shape of the failure rather than its volume: - It is an unguarded null dereference on **our** code path. Every frame between the throw site and the thread-pool dispatch belongs to Metalama. - It kills the whole design-time pipeline execution for the project, so the user sees generated source disappear rather than a diagnostic. - The client sends **one report per problem per version**, so one report is one installation that met it on one version, not one occurrence. A defect on a deterministic code path is hit on every keystroke that retriggers the generator; it is reported once. ## Version history Observed **only in 2026.1.16**, on 2026-06-04. Never observed in any other lineage: not in 2026.0, not in 2025.1. `2026.1.16` is the first stable release of the 2026.1 line (published 2026-06-03) and it is **not retired**, so this is current software. A single lineage normally reads as **a regression introduced in that lineage**, and here that reading is supported by a specific change (below) rather than by the absence alone. One caveat on the absence, so nobody over-reads it: from **2026.1.19** on, sending a crash report requires the user's consent, where it used to be automatic. So the 2026.1 line reports very little above 2026.1.18 for every defect, and the fact that this has not been seen since 2026-06-04 is **not** evidence that it was fixed. ## Where to look, as two hypotheses a maintainer can check faster than I can Neither is a claim. Both come from reading the stack against closed issues in this repository. **1. `#1622` may have opened this path.** `#1622` ("Introduced constructor on introduced type missing at design time", closed as completed, milestone **2026.1.12-preview**) changed exactly the two frames below the throw site. Its root-cause section says `DesignTimeSyntaxTreeGenerator` filtered introduced constructors out with `.Where(t => t.Observability == TransformationObservability.Always)`, and its fix keeps such a constructor observable so that the design-time generator now calls `IntroduceConstructorTransformation.GetInjectedMembers`, which is frame 5 here. The first stable to carry that fix is in the 2026.1 line, and this crash appears in 2026.1.16 and in no earlier lineage. So the plausible sequence is that the constructor path became reachable at design time and then met an attribute it could not render. Worth confirming or dismissing from the source; I cannot tell from crash reports whether the path was wholly unreachable before, only that the timing fits. **2. The enumerated collection is probably the attribute constructor's parameters, and `#658` touched that code.** `Enumerable.TryGetLastNonIterator` is what `Last()` / `LastOrDefault()` calls for a non-indexable sequence, so `ContextualSyntaxGenerator.Attribute` is taking the **last element of a `DeclarationCollection`**. The obvious reason to want the last parameter of an attribute constructor is to detect a `params` array, and `#658` ("Incorrect code generation when introducing attribute with null params argument", closed as completed, milestone 2026.1.4-preview) names `ContextualSyntaxGenerator.Attribute` as a suspect for precisely the `params` handling. `#658` shipped **before** 2026.1.16, so it is not the fix for this and this is not a regression from it; the value of the reference is that it points at the lines that do this. If both hold, the failing case is an attribute on an **introduced** constructor whose `IAttributeData` resolves a constructor reference that the design-time compilation model cannot enumerate, which would make the null the collection's source rather than anything in the user's code. ## Suggested fix Independently of which hypothesis is right, two things would hold either way: 1. **Guard the enumeration in `ContextualSyntaxGenerator.Attribute`.** Taking the last parameter of an attribute constructor should not be able to throw an unhandled `NullReferenceException`; if the collection cannot be resolved, that is a condition to report as a diagnostic. 2. **Do not let one transformation's failure abort the whole design-time syntax-tree generation.** The user's symptom here is that generated source vanishes for the project, which is much larger than the underlying defect. ## Not these issues Named so nobody links them later: - **`#1622`** (closed, completed, 2026.1.12-preview): different symptom, an introduced constructor **missing** from the design-time output, not a crash. Same two frames, and it is referenced above as a possible cause rather than a duplicate. - **`#658`** (closed, completed, 2026.1.4-preview): different symptom, **incorrect generated code** for an attribute with a null `params` argument, not a crash, and it shipped before the version seen here. - **`#652`** (closed, completed, 2026.1.5-preview): design-time introduction of a constructor **parameter** of an introduced type. A feature, adjacent area, different thing. - **`#598`** (closed): the only other issue in either organisation mentioning `DeclarationCollection`. An assertion failure implementing a generic interface on an introduced generic type. Different exception, different path. `GetAttributeLists`, `AttributesForDeclaration` and `TryGetLastNonIterator` return **no** issues at all in either the `metalama` or the `postsharp` organisation, open or closed. ## Provenance Filed from the CEIP crash-report database. Invariant problem id **29257**. Every figure above is over the retained window of 90 days; the crash reports themselves are deleted after that, so this issue is the only surviving record. No user description was submitted with this report. The report contains no project, assembly, type or file name: the stack is entirely framework and Metalama symbols, and the exception message is the stock BCL string.