Summary
I have a compile time utilities class that has some convenience methods. It's in one package, and I'm pulling it into another via nuget. These methods are written as extension methods.
The problem I was seeing was that I get a FileNotFound exception when calling one of these extension methods within a method called from the BuildEligibility method in a MethodOverrideAspect implementation.
Errors and Warnings
Here's the original error messages, hopefully it will help associate this report with the automated one.
This one's from the console:
3>CSC: Error LAMA0001 : Unexpected exception occurred in Metalama: 'Exception of type 'System.IO.FileNotFoundException' thrown while evaluating eligibility for aspect 'SetContext' applied to 'ContextAspectsGenerationUnitTests.DoTheThing3(int, int)'': Could not load file or assembly 'ml!FlyingChi.Primitives.Aspects_5576dec0bb9a13fe, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified. Exception details are in 'C:\Users\albet\AppData\Local\Temp\Metalama\CrashReports\exception-0038a878-051a-4509-82a2-9ce7cd9fbe43.txt'. Please report this issue at https://www.postsharp.net/support and attach this file to the ticket. You may want to remove sensitive data from the report.
Here's the one from the specified file:
Metalama Version: 2026.1.19
Runtime: .NET 8.0.11
Processor Architecture: X64
OS Description: Microsoft Windows 10.0.26200
OS Architecture: X64
Exception type: Metalama.Framework.Engine.Utilities.UserCode.UserCodeException
Exception message: 'Exception of type 'System.IO.FileNotFoundException' thrown while evaluating eligibility for aspect 'SetContext' applied to 'ContextAspectsGenerationUnitTests.DoTheThing3(int, int)'': Could not load file or assembly 'ml!FlyingChi.Primitives.Aspects_5576dec0bb9a13fe, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
===== Exception =====
Metalama.Framework.Engine.Utilities.UserCode.UserCodeException: 'Exception of type 'System.IO.FileNotFoundException' thrown while evaluating eligibility for aspect 'SetContext' applied to 'ContextAspectsGenerationUnitTests.DoTheThing3(int, int)'': Could not load file or assembly 'ml!FlyingChi.Primitives.Aspects_5576dec0bb9a13fe, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
---> System.IO.FileNotFoundException: Could not load file or assembly 'ml!FlyingChi.Primitives.Aspects_5576dec0bb9a13fe, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. The system cannot find the file specified.
File name: 'ml!FlyingChi.Primitives.Aspects_5576dec0bb9a13fe, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
at FlyingChi.Context.Aspects.SetContextAttribute.ProduceValidationFailureMessage(FormattableString description, IMethod method)
at FlyingChi.Context.Aspects.SetContextAttribute.<BuildEligibility>b__20_0(IMethod parameter) in C:\Users\albet\AppData\Local\Temp\Metalama\CompileTime\FlyingChi.Context.Aspects\.netstandard2.1\403005c365cd35e7\2026.1.19\SetContextA_142f441a.cs:line 82
at Metalama.Framework.Eligibility.Implementation.EligibilityRule`1.GetEligibility(T obj)
at Metalama.Framework.Eligibility.Implementation.AndEligibilityRule`1.GetEligibility(T obj)
at Metalama.Framework.Engine.Aspects.EligibilityHelper.<>c__DisplayClass12_0.<GetEligibility>g__GetEligibilityCore|0()
at Metalama.Framework.Engine.Utilities.UserCode.UserCodeInvoker.Invoke[TResult,TPayload](UserCodeFunc`2 func, TPayload& payload, UserCodeExecutionContext context, Boolean wrapException)
--- End of inner exception stack trace ---
at Metalama.Framework.Engine.Utilities.UserCode.UserCodeInvoker.Invoke[TResult,TPayload](UserCodeFunc`2 func, TPayload& payload, UserCodeExecutionContext context, Boolean wrapException)
at Metalama.Framework.Engine.Aspects.EligibilityHelper.GetEligibility(IDeclaration obj, Boolean isInheritable)
at Metalama.Framework.Engine.Aspects.AspectInstance.ComputeEligibility(IDeclaration declaration)
at Metalama.Framework.Engine.Aspects.CompilationAspectSource.<>c__DisplayClass9_0.<CollectAspectInstancesAsync>g__ProcessAttribute|0(IAttribute attribute)
at Metalama.Framework.Engine.Utilities.Threading.ConcurrentTaskRunner.<>c__DisplayClass1_0`1.<RunConcurrentlyAsync>g__ProcessQueue|0()
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
--- End of stack trace from previous location ---
at System.Threading.ExecutionContext.RunFromThreadPoolDispatchLoop(Thread threadPoolThread, ExecutionContext executionContext, ContextCallback callback, Object state)
at System.Threading.Tasks.Task.ExecuteWithThreadLocal(Task& currentTaskSlot, Thread threadPoolThread)
--- End of stack trace from previous location ---
at Metalama.Framework.Engine.Pipeline.PipelineStepsState.ExecuteAspectSourceAsync(CompilationModel compilation, IAspectClass aspectClass, IEnumerable`1 aspectSources, IUserDiagnosticSink diagnosticSink, CancellationToken cancellationToken)
at Metalama.Framework.Engine.Pipeline.EvaluateAspectSourcesPipelineStep.ExecuteAsync(CompilationModel compilation, UserDiagnosticSink diagnostics, Int32 stepIndex, CancellationToken cancellationToken)
at Metalama.Framework.Engine.Pipeline.PipelineStepsState.ExecuteAsync(CancellationToken cancellationToken)
at Metalama.Framework.Engine.Pipeline.HighLevelPipelineStage.ExecuteAsync(AspectPipelineConfiguration pipelineConfiguration, AspectPipelineResult input, IDiagnosticAdder diagnostics, TestableCancellationToken cancellationToken)
at Metalama.Framework.Engine.Pipeline.AspectPipeline.ExecuteAsync(PartialCompilation compilation, IDiagnosticAdder diagnosticAdder, AspectPipelineConfiguration pipelineConfiguration, TestableCancellationToken cancellationToken)
at Metalama.Framework.Engine.Pipeline.CompileTime.CompileTimeAspectPipeline.ExecuteCoreAsync(IDiagnosticAdder diagnosticAdder, PartialCompilation compilation, ImmutableArray`1 resources, AspectPipelineConfiguration configuration, TestableCancellationToken cancellationToken)
at Metalama.Framework.Engine.Pipeline.CompileTime.CompileTimeAspectPipeline.ExecuteAsync(Action`1 reportDiagnostic, Action`1 reportSuppression, Compilation compilation, ImmutableArray`1 resources, TestableCancellationToken cancellationToken)
Code to Reproduce
// Here's the method that was being called when compilation failed
/// <summary>
/// Evaluates whether the type is a Result or task result of some kind
/// </summary>
/// <param name="type">The type to evaluate</param>
/// <returns>A formattable string describing the type requirements, if the type does not meet them</returns>
public static bool IsResultTask(this IType type)
{
if (type.IsConvertibleTo(typeof(Result.Result<>), ConversionKind.TypeDefinition) ||
type.IsConvertibleTo(typeof(Result.Result<,>), ConversionKind.TypeDefinition))
{
// Results are fine and handled by the OverrideMethod template.
return true;
}
if ((type.IsConvertibleTo(typeof(Task<>), ConversionKind.TypeDefinition) ||
type.IsConvertibleTo(typeof(ValueTask<>), ConversionKind.TypeDefinition)) &&
type is IGeneric genericType &&
(genericType.TypeArguments[0].IsConvertibleTo(typeof(Result.Result<>), ConversionKind.TypeDefinition) ||
genericType.TypeArguments[0].IsConvertibleTo(typeof(Result.Result<,>), ConversionKind.TypeDefinition)))
{
// Awaitable things that contain results are fine and handled by the OverrideAsyncMethod template
return true;
}
return false;
}
// Here's the method where the previous one is being called
/// <summary>
/// Evaluates whether the type is a valid return value for <see cref="ContextAttribute"/>
/// </summary>
/// <param name="description">A description string used in the final error message</param>
/// <param name="method">The method to evaluate</param>
/// <returns>A formattable string describing the validation requirements, if the target does not meet them</returns>
private FormattableString ProduceValidationFailureMessage(FormattableString description, IMethod method)
{
if (!AspectUtilities.IsResultTask(method.ReturnType))
{
return $"{description} must return a result object, or a task result object";
}
return null;
}
Versions
- Metalama: 2026.1.19
- .NET SDK: 8.0.404
- Target Framework:netstandard2.1
- OS: Windows 11 Home
- Processor Architecture : AMD64
Additional context
I submitted a bug report from the automatic reporter a little while ago, but I was experimenting and I found a couple weird quirks about it, and I wanted to share in case it's helpful in your debugging efforts.
The first weird quirk that I just noticed was that if I made it a regular static method call instead of using the extension method syntax, everything works fine. I thought that was pretty weird, but in any case, I have a workaround.
The second weird quirk that I noticed was that I successfully use the other methods from that utility class as extension methods in the OverrideMethod and OverrideAsyncMethod methods. Seems pretty weird that it would work in one method but not another.
I know that sometimes those kinds of quirks end up being leads to investigate when I'm debugging things, so I thought they might be helpful for you.
Summary
I have a compile time utilities class that has some convenience methods. It's in one package, and I'm pulling it into another via nuget. These methods are written as extension methods.
The problem I was seeing was that I get a FileNotFound exception when calling one of these extension methods within a method called from the BuildEligibility method in a MethodOverrideAspect implementation.
Errors and Warnings
Here's the original error messages, hopefully it will help associate this report with the automated one.
This one's from the console:
Here's the one from the specified file:
Code to Reproduce
Versions
Additional context
I submitted a bug report from the automatic reporter a little while ago, but I was experimenting and I found a couple weird quirks about it, and I wanted to share in case it's helpful in your debugging efforts.
The first weird quirk that I just noticed was that if I made it a regular static method call instead of using the extension method syntax, everything works fine. I thought that was pretty weird, but in any case, I have a workaround.
The second weird quirk that I noticed was that I successfully use the other methods from that utility class as extension methods in the OverrideMethod and OverrideAsyncMethod methods. Seems pretty weird that it would work in one method but not another.
I know that sometimes those kinds of quirks end up being leads to investigate when I'm debugging things, so I thought they might be helpful for you.