dotnet/efcore · error · InvalidOperationException

Invocation: Found matches for generic method

Error message

Invocation: Found {definitionMethodInfos.Length} matches for generic method: {invocation}

What it means

Thrown when resolving a generic method's open definition via reflection yields zero or more than one match. After building a detailed signature comparison (name, generic arity, parameter count, and resolved parameter types mapped through generic type parameters), the translator expects exactly one candidate. If it finds 0 or 2+ matches, the Roslyn symbol and the reflection metadata are inconsistent and it throws InvalidOperationException.

Solutions

  1. Reduce ambiguity: if you control the method, rename overloads so only one generic method with that name and arity exists on the type.
  2. Check for assembly version mismatches between the compilation references and the runtime-loaded assemblies — ensure the same version of all packages is used consistently.
  3. If the method is an extension method, try calling it as a static method explicitly to see if that resolves the ambiguity differently.
  4. Simplify the generic call — avoid using methods where the same name appears with the same arity and parameter count but different constraints or type mappings.

Example fix

// before — ambiguous overloads
// public static T Pick<T>(this T a, T b);
// public static T Pick<T>(this T a, T b) where T: struct;
var query = ctx.Values.Select(x => MyExtensions.Pick(x, x));

// after — disambiguate by renaming or using a non-ambiguous helper
var query = ctx.Values.Select(x => x);
Defensive patterns

Strategy: validation

Validate before calling

// Before precompiling, verify generic methods have unambiguous reflection resolution
foreach (var invocation in querySyntaxTree.DescendantNodes().OfType<InvocationExpressionSyntax>())
{
    if (semanticModel.GetSymbolInfo(invocation).Symbol is IMethodSymbol { IsGenericMethod: true } method)
    {
        var declaringType = ResolveTypeForCheck(method.ContainingType);
        var matches = declaringType.GetMethods()
            .Count(m => m.Name == method.Name && m.IsGenericMethodDefinition
                && m.GetGenericArguments().Length == method.OriginalDefinition.TypeParameters.Length);
        if (matches != 1)
            ReportError($"Ambiguous generic method '{method.Name}' has {matches} reflection matches");
    }
}

Prevention

When it happens

Trigger: A precompiled query calls a generic method where: (a) reflection GetMethods returns multiple methods matching the same name/arity/parameter-signature after type-parameter resolution (ambiguous overloads in the declaring type), or (b) no method matches because the Roslyn-resolved parameter types differ from the reflection parameter types (e.g. due to type forwarding, remapped types, or compiler-generated wrapper types).

Common situations: Calling custom generic extension methods with overloaded signatures that differ only in generic constraints; calling framework generic methods whose containing type was loaded from a different assembly version than Roslyn analyzed; using F# or VB-compiled libraries where generic parameter naming conventions differ; calling methods with ref/out or in parameters that the translator's parameter-type resolution handles differently.

Related errors


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

Appendix: source

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

                        for (var i = 0; i < candidateParams.Length; i++)
                        {
                            var translatedParamType = ResolveType(originalDefinition.Parameters[i].Type, methodTypeParameterMap);
                            if (translatedParamType != candidateParams[i].ParameterType)
                            {
                                return false;
                            }
                        }

                        return true;
                    }

                    return false;
                }).ToArray();

            if (definitionMethodInfos.Length != 1)
            {
                throw new InvalidOperationException(
                    $"Invocation: Found {definitionMethodInfos.Length} matches for generic method: {invocation}");
            }

            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)

View on GitHub (pinned to 3a2006ef56)