Repository navigation
Generators: LAMA0041 now and then when IntroduceMethod copies a template's attributes #109
Description
Problem
A build fails now and then with LAMA0041 when one of our aspects introduces a method from a template. The next build of the same tree passes. It last happened on 2026-10-28, in the first local build of release/2.3.0 at a184c29, right after a branch switch that changed the Generators' sources:
test/CodoMetis.TypeKit.Generators.Probes/Probes.cs:75
LAMA0041 'Exception of type 'System.InvalidOperationException' thrown while executing BuildAspect for aspect
[ValueObjectParsableAspect] applied to 'ProbeDescending': Operation is not valid due to the current state of the object.
A re-run of the same command, with no change in between, passed: 18,092 passed and 471 skipped. CI built the same tree green on #107.
Stack
From Metalama's crash report (~/Library/Application Support/Metalama/Temp/CrashReports/exception-40c7cdd6-….txt, Metalama 2026.1.30):
System.InvalidOperationException: Operation is not valid due to the current state of the object.
at Metalama.Framework.Engine.CodeModel.References.AttributeRef.Metalama.Framework.Code.IRef.GetTargetInterface(ICompilation compilation, Type interfaceType, IGenericContext genericContext, Boolean throwIfMissing)
at Metalama.Framework.Engine.CodeModel.Collections.DeclarationCollection`2.GetItem(TRef reference)
at Metalama.Framework.Engine.CodeModel.Collections.DeclarationCollection`2.GetEnumerator()+MoveNext()
at System.Linq.Enumerable.IEnumerableWhereSelectIterator`2.MoveNext()
at Metalama.Framework.Engine.CodeModel.Introductions.Builders.DeclarationBuilder.AddAttributes(IEnumerable`1 attributes)
at Metalama.Framework.Engine.AdviceImpl.Introduction.IntroduceMethodAdvice.InitializeBuilderCore(MethodBuilder builder, TemplateAttributeProperties templateAttributeProperties, AdviceImplementationContext context)
at Metalama.Framework.Engine.AdviceImpl.Introduction.IntroduceMemberAdvice`3.InitializeBuilder(TBuilder builder, AdviceImplementationContext context)
at Metalama.Framework.Engine.AdviceImpl.Introduction.IntroduceDeclarationAdvice`2.Implement(AdviceImplementationContext context)
at Metalama.Framework.Engine.Advising.Advice`1.Execute(IAdviceExecutionContext context)
at Metalama.Framework.Engine.Advising.AdviceFactory`1.IntroduceMethod(INamedType targetType, String defaultTemplate, IntroductionScope scope, OverrideStrategy whenExists, Action`1 buildMethod, Object args, Object tags)
at CodoMetis.TypeKit.Generators.ValueObjectParsableAspect.IntroduceParse(IAspectBuilder`1 builder, String template, String name)
at CodoMetis.TypeKit.Generators.ValueObjectParsableAspect.BuildAspect(IAspectBuilder`1 builder)
at Metalama.Framework.Engine.Utilities.UserCode.UserCodeInvoker.<>c__DisplayClass7_0.<TryInvoke>b__0()
at Metalama.Framework.Engine.Utilities.UserCode.UserCodeInvoker.Invoke[TResult,TPayload](UserCodeFunc`2 func, TPayload& payload, UserCodeExecutionContext context, Boolean wrapException)
at Metalama.Framework.Engine.Utilities.UserCode.UserCodeInvoker.TryInvoke[TResult,TPayload](UserCodeFunc`2 func, TPayload& payload, UserCodeExecutionContext context, TResult& result)
Not one aspect: three occurrences, one path
This machine's crash-report folder has 7,236 reports. Three of them have this stack, each from a different aspect, and each comes from IntroduceMethod with a template:
| Date | Aspect frame |
|---|---|
| 2026-10-14 19:05 | ValueObjectFormattableAspect.BuildAspect |
| 2026-10-16 17:49 | ValueObjectAspect.IntroduceEntryPoint |
| 2026-10-28 23:10 | ValueObjectParsableAspect.IntroduceParse |
It is not known whether the two older reports came from a CLI build or from the IDE's design-time pipeline.
What throws (Metalama release/2026.1, the same on develop/2026.1)
AttributeRef.GetTargetInterface throws a bare InvalidOperationException when GetTargetOrNull returns null. For an attribute read from a symbol, that is SymbolAttributeRef.TryGetTarget, which returns false when !_attributeData.IsValid(). So while the advice copied the template method's attributes onto the introduced method, one attribute's AttributeData was not valid: an attribute class or constructor that did not resolve. Our code is the same each time, so the state that differs between builds is Metalama's: the compilation or the compile-time assembly it read the template's attributes from.
Is it the #2303 race? No, not that code
metalama/Metalama#2303, the OfName race, is fixed by metalama/Metalama#2309, merged on 2026-10-28 into develop/2026.1. It is not in a release yet: 2026.1.30 is from 2026-10-13. That PR changes only NonUniquelyNamedUpdatableCollection<T>.OfName, the by-name index of a code-model collection. This stack has no OfName call and no updatable collection: it enumerates a template's attribute references and finds one whose AttributeData is invalid. #2309 does not touch AttributeRef, SymbolAttributeRef or DeclarationCollection.
Whether it is a race at all is not shown yet. It is intermittent, the input is the same, and Metalama runs aspect callbacks on several threads. But a compile-time cache read while it is being rebuilt would fit as well, and the 2026-10-28 build was the first after the Generators' sources changed.
Next
- Reproduce it: build the Probes project in a loop after touching a Generators source, once as it is and once with
MetalamaConcurrentBuildEnabled=false. That setting made #2303's repro pass in 80 of 80 builds (seespikes/ConcurrentNamespaceTypes/README.mdfor how that race was measured here). - With a repro, or with the three reports if none comes, report it upstream to Metalama, linking #2303 as a different path.
- There is no workaround in TypeKit yet: the attribute copy is Metalama's, inside
IntroduceMethod. A repro would show which of the template's attributes is invalid, and whether a template without it avoids the crash.
Activity
CaffeinatedCoder commentedon Oct 29, 2026
Not reproduced on the Probes project: 0 failures in 400 builds (2026-10-29).
Each build followed an edit of a Generators source (a numbered comment appended to
ValueObjectParsableAspect.Templates.cs), so each one compiled a fresh compile-time project, a new directory under Metalama'sCompileTimecache, and wove the Probes again: the condition of the 2026-10-28 crash. The two modes alternated build by build, so drift over time affected both alike.MetalamaConcurrentBuildEnabled=falseNo crash report with this stack was written during the run. The command was
build-verdict.dll build test/CodoMetis.TypeKit.Generators.Probes/…csproj [-- -p:MetalamaConcurrentBuildEnabled=false], in a worktree ofrelease/2.3.0ata184c29.So the flag cannot be judged from this run, and a Probes-only build is likely not the trigger. What the 2026-10-28 build had and these did not: it was a solution build (
build-verdict test), in which several projects that weave with the Generators build in parallel, as separate compilations each needing the same freshly changed compile-time project. A race between those, on the cache or on the compilation, fits all three reports. The next run would loop solution builds after the same edit.CaffeinatedCoder commentedon Oct 29, 2026
Not reproduced on solution builds either: 0 failures in 44 builds (2026-10-29, a run kept under five minutes).
The same edit came before each build. Each one was a solution build,
build-verdict.dll build CodoMetis.TypeKit.slnx, in a worktree ofrelease/2.3.0ata184c29. After the edit it rebuilds the Generators and weaves six projects in parallel: AspNetCore.Tests, EntityFrameworkCore.Tests, Generators.Probes, Generators.Tests, Samples and Serilog.Tests.MetalamaConcurrentBuildEnabled=falseNo crash report with this stack was written. Together with the 400 Probes builds, that is 0 in 444 builds after a Generators edit. At three crashes in about two weeks of ordinary work, the rate is far lower than the earlier runs could show, or a condition is missing that these runs did not have. One candidate is an IDE design-time build running beside a CLI build: the two older reports may have come from Rider. Another is the first build after a branch switch, which changes many sources and the restore at once, not one comment.
Next: keep the crash reports. If it happens again, note what was running alongside (the IDE, a second build) and what changed just before, and add it here. With a fourth report, or a repro, report it upstream, linking metalama/Metalama#2303 as a different path.
CaffeinatedCoder commentedon Oct 29, 2026
Closed as not reproduced: 0 failures in 444 builds after a Generators edit (400 of the Probes project, 44 of the solution, each half with MetalamaConcurrentBuildEnabled=false). Reopen with a fourth crash report or a repro, noting what ran alongside and what changed just before.