Open sandboxFocusImprove this doc

LAMA0041: Compile-time code throws an exception

Severity Error
Reported by Metalama.Framework
Message An exception of type '<ExceptionType>' was thrown while <Activity>: <ExceptionMessage>. Exception details are in '<DetailsPath>'. To attach a debugger to the compiler, use the '-p:MetalamaDebugCompiler=True' command-line option.

Cause

During compilation, Metalama executes your compile-time code: the BuildAspect and BuildEligibility methods of aspects, templates, fabrics, validators, and the constructors of these types. Metalama reports LAMA0041 when this code throws an exception that it doesn't handle.

In the message:

  • <Activity> describes what Metalama was executing, for instance executing BuildAspect for aspect [LogAttribute] applied to 'Calculator.Add(int, int)' or executing the template method 'LogAttribute.OverrideMethod()';
  • <ExceptionType> and <ExceptionMessage> are the type and the message of the exception;
  • <DetailsPath> is the path of a text file that contains the complete exception, including its stack trace, or (none) when no file was written.

When possible, the error is reported on the target declaration of the aspect.

Some exceptions are thrown by Metalama itself, but are caused by the aspect code. For instance, Metalama throws an InvalidOperationException when an aspect adds an advice to a declaration for which this advice isn't eligible. Such exceptions are also reported as LAMA0041, and their message explains the problem.

In the following example, the Log aspect throws an exception when its Category property isn't set, and the aspect is applied without setting it.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5namespace Doc.LAMA0041.Error;
6
7public class LogAttribute : OverrideMethodAspect
8{
9    public string? Category { get; set; }
10
11    public override void BuildAspect( IAspectBuilder<IMethod> builder )
12    {
13        // The aspect throws an exception when the Category property isn't set.
14        if ( this.Category == null )
15        {
16            throw new InvalidOperationException( "The Category property of the [Log] aspect must be set." );
17        }
18
19        base.BuildAspect( builder );
20    }
21
22    public override dynamic? OverrideMethod()
23    {
24        Console.WriteLine( $"{this.Category}: executing {meta.Target.Method}." );
25
26        return meta.Proceed();
27    }
28}
29
1namespace Doc.LAMA0041.Error;
2
3internal class Calculator
4{
5    // Error: the aspect throws an exception because Category isn't set.
6    [Log]
    Error LAMA0041: An exception of type 'System.InvalidOperationException' was thrown while executing BuildAspect for aspect [LogAttribute] applied to 'Calculator.Add(int, int)': The Category property of the [Log] aspect must be set. Exception details are in '(none)'. To attach a debugger to the compiler, use the '-p:MetalamaDebugCompiler=True' command-line option.

7    public int Add( int a, int b ) => a + b;
8}
9

Resolution

Read the exception message and type in the diagnostic message. If they aren't enough to find the cause, open the file given at the end of the message to see the stack trace.

Then, depending on the situation:

  • If you're using the aspect, make sure that you're using it as its author intended, for instance by setting its required properties. The following example sets the Category property.
  • If you're the author of the aspect, fix the bug. Instead of throwing exceptions for invalid usages, define eligibility conditions in BuildEligibility, or report an error with builder.Diagnostics.Report and skip the aspect with builder.SkipAspect(). Before adding an advice, check its eligibility with the IsAdviceEligible extension method of the target declaration.
  • To debug the compile-time code, build the project with the -p:MetalamaDebugCompiler=True command-line option, which lets you attach a debugger to the compiler.

1using Metalama.Framework.Aspects;
2using Metalama.Framework.Code;
3using System;
4
5namespace Doc.LAMA0041.Fixed;
6
7public class LogAttribute : OverrideMethodAspect
8{
9    public string? Category { get; set; }
10
11    public override void BuildAspect( IAspectBuilder<IMethod> builder )
12    {
13        // The aspect throws an exception when the Category property isn't set.
14        if ( this.Category == null )
15        {
16            throw new InvalidOperationException( "The Category property of the [Log] aspect must be set." );
17        }
18
19        base.BuildAspect( builder );
20    }
21
22    public override dynamic? OverrideMethod()
23    {
24        Console.WriteLine( $"{this.Category}: executing {meta.Target.Method}." );
25
26        return meta.Proceed();
27    }
28}
29
Source Code
1namespace Doc.LAMA0041.Fixed;
2


3internal class Calculator
4{
5    // Fixed: Category is set, so the aspect doesn't throw.
6    [Log( Category = "Math" )]
7    public int Add( int a, int b ) => a + b;
8}
9
Transformed Code
1using System;
2
3namespace Doc.LAMA0041.Fixed;
4
5internal class Calculator
6{
7    // Fixed: Category is set, so the aspect doesn't throw.
8    [Log(Category = "Math")]
9    public int Add(int a, int b)
10    {
11        Console.WriteLine("Math: executing Calculator.Add(int, int).");
12        return a + b;
13    }
14}
15

See also