Skip to content

Generators: LAMA0041 now and then when IntroduceMethod copies a template's attributes #109

Closed as not planned

Description

@CaffeinatedCoder

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 (see spikes/ConcurrentNamespaceTypes/README.md for 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

  1. added this to the 2.3.0 milestone on Oct 29, 2026
  2. added
    bugSomething isn't working
    severity/mediumInconsistency or failure in a narrow scenario
    package/generatorsAffects CodoMetis.TypeKit.Generators
    area/value-objectsValue-object contracts and what the aspects generate for them
    on Oct 29, 2026
  3. CaffeinatedCoder commented on Oct 29, 2026

    @CaffeinatedCoder
    OwnerAuthor

    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's CompileTime cache, 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.

    Mode Builds LAMA0041 Other failures Mean build
    default 200 0 0 2.0 s
    MetalamaConcurrentBuildEnabled=false 200 0 0 2.3 s

    No 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 of release/2.3.0 at a184c29.

    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.

  4. CaffeinatedCoder commented on Oct 29, 2026

    @CaffeinatedCoder
    OwnerAuthor

    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 of release/2.3.0 at a184c29. 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.

    Mode Builds LAMA0041 Other failures Mean build
    default 22 0 0 4.1 s
    MetalamaConcurrentBuildEnabled=false 22 0 0 5.5 s

    No 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.

  5. CaffeinatedCoder commented on Oct 29, 2026

    @CaffeinatedCoder
    OwnerAuthor

    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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/value-objectsValue-object contracts and what the aspects generate for thembugSomething isn't workingpackage/generatorsAffects CodoMetis.TypeKit.Generatorsseverity/mediumInconsistency or failure in a narrow scenario

    Projects

    No projects

      Milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions