dotnet/efcore · error · InvalidOperationException

Invocation: couldn't find method

Error message

Invocation: couldn't find method '{methodSymbol.Name}' on type '{declaringType.Name}': {invocation}

What it means

Thrown when a non-generic method cannot be found on the declaring type via reflection GetMethod(name, bindings, paramTypes). The Roslyn symbol gave the method name and parameter types, but Type.GetMethod returned null. This means Roslyn sees the method but the loaded CLR type does not expose it under the same name and signature.

Solutions

  1. Verify the method is public or that InternalsVisibleTo is set for the precompilation assembly.
  2. Check for assembly version mismatches — ensure all referenced packages are at consistent versions between compile and precompile phases.
  3. If the method is an explicit interface implementation, call it through the interface type instead of the implementing type.
  4. Pass the external assembly containing the declaring type via the additionalAssembly parameter of CSharpToLinqTranslator.Load().
  5. If the method has ref/out/in parameters, the translator's parameter-type resolution may not match the reflection signature — restructure to avoid passing by reference.

Example fix

// before — calling internal method from different assembly
var query = ctx.Items.Where(x => x.CalculateInternalScore() > 10);

// after — make method public, or move logic into the query
var query = ctx.Items.Where(x => x.Score > 10);
Defensive patterns

Strategy: validation

Validate before calling

// Before precompiling, verify non-generic methods are findable via reflection
foreach (var invocation in querySyntaxTree.DescendantNodes().OfType<InvocationExpressionSyntax>())
{
    if (semanticModel.GetSymbolInfo(invocation).Symbol is IMethodSymbol { IsGenericMethod: false } method)
    {
        var declaringType = ResolveTypeForCheck(method.ContainingType);
        var paramTypes = method.Parameters.Select(p => ResolveTypeForCheck(p.Type)).ToArray();
        var found = declaringType.GetMethod(method.Name,
            BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
            null, CallingConventions.Any, paramTypes, null);
        if (found is null)
            ReportError($"Method '{method.Name}' not found via reflection on {declaringType.Name}");
    }
}

Prevention

When it happens

Trigger: A precompiled query calls a non-generic instance or static method where: the method is private/internal and BindingFlags resolution differs; the method's parameter types resolved through ResolveType differ from the actual reflection parameter types; the declaring type loaded at runtime is a different version than what Roslyn compiled against; the method is an explicit interface implementation (maps to a different name in metadata); or the method is compiler-generated.

Common situations: Calling internal methods from a different assembly without InternalsVisibleTo; version skew between the NuGet package referenced at compile time and the one loaded at runtime; calling methods on types from assemblies not passed via additionalAssembly; explicit interface implementation methods whose metadata name includes the interface prefix; methods with optional/ref parameters that change the reflection signature lookup.

Related errors


AI-assisted analysis of dotnet/efcore@3a2006ef56 (2026-08-11). Data as JSON: /api/errors/df1bcba40706ef1b. Report an issue: GitHub.

Appendix: source

Thrown at src/EFCore.Design/Query/Internal/CSharpToLinqTranslator.cs:647

            }

            var definitionMethodInfo = definitionMethodInfos[0];
            var typeParams = methodSymbol.TypeArguments.Select(a => ResolveType(a)).ToArray();
            methodInfo = definitionMethodInfo.MakeGenericMethod(typeParams);
        }
        else
        {
            // Non-generic method
            var reducedMethodSymbol = methodSymbol.ReducedFrom ?? methodSymbol;

            methodInfo = declaringType.GetMethod(
                methodSymbol.Name,
                BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static,
                reducedMethodSymbol.Parameters.Select(p => ResolveType(p.Type)).ToArray());

            if (methodInfo is null)
            {
                throw new InvalidOperationException(
                    $"Invocation: couldn't find method '{methodSymbol.Name}' on type '{declaringType.Name}': {invocation}");
            }
        }

        // We have the reflection MethodInfo for the method, prepare the arguments.

        // We can have less arguments than parameters when the method has optional parameters; fill in the missing ones with the default
        // value.
        // If the method also has a "params" parameter, we also need to take care of that - the syntactic arguments will need to be packed
        // into the "params" array etc.
        var parameters = methodInfo.GetParameters();
        var sourceArguments = invocation.ArgumentList.Arguments;
        var destArguments = new Expression?[parameters.Length];
        var paramIndex = 0;

        // At the syntactic level, an extension method invocation looks like a normal instance's.
        // Prepend the instance to the argument list.
        // TODO: Test invoking extension without extension syntax (as static)

View on GitHub (pinned to 3a2006ef56)