pardeike/Harmony · error · AmbiguousMatchException
Multiple possible indexers were found.
Error message
Multiple possible indexers were found.
What it means
AccessTools.DeclaredIndexer searches a type for a declared indexer matching the given parameters. When the underlying Type.GetProperties/MemberInfo query reports multiple candidates, the InvalidOperationException is caught and rethrown as an AmbiguousMatchException with the message 'Multiple possible indexers were found.' plus the original as InnerException.
Solutions
- Pass an explicit parameters array that uniquely identifies the indexer you want
- Disambiguate manually: get the property via type.GetProperties() and pick by indexer parameter type, then use its GetMethod/SetMethod
- If the duplicate indexers come from generated/COM metadata, use the specific interface or declaring type that has only one indexer
Example fix
// before
var getter = AccessTools.DeclaredIndexerGetter(typeof(Table)); // multiple indexers
// after
var getter = AccessTools.DeclaredIndexerGetter(typeof(Table), new[] { typeof(string) }); Defensive patterns
Strategy: try-catch
Validate before calling
var indexers = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
.Where(p => p.GetIndexParameters().Length > 0).ToArray();
if (indexers.Length > 1)
throw new AmbiguousMatchException($"{typeof(T)} has {indexers.Length} indexers; pass explicit parameters"); Try / catch
try { var getter = AccessTools.DeclaredIndexerGetter(type, paramTypes); }
catch (AmbiguousMatchException ex) { /* enumerate type.GetProperties() and pick the indexer manually */ } Prevention
- Always pass explicit parameter types when a type could have multiple indexers
- Inspect the type with GetProperties().Where(p => p.GetIndexParameters().Length > 0) during development
- Avoid relying on default indexer resolution for COM or generated types with duplicate metadata
When it happens
Trigger: Calling DeclaredIndexer (or DeclaredIndexerGetter/DeclaredIndexerSetter which call it) on a type whose binding flags/parameter matching cannot disambiguate between two or more indexers with compatible signatures — e.g. indexers differing only by parameter type when empty parameters are given.
Common situations: Types with several overloaded indexers (this[int], this[string]) where the caller passes no parameter array so Harmony cannot pick one; COM interop types with duplicate indexer metadata; generic type hierarchies with redeclared indexers.
Related errors
- Method has wrong return type (should be assignable to )
- Null method for
- You can only patch implemented methods/constructors. Patch…
- Null method for
- Field must not be static
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/0f815879dd32b141.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Tools/AccessTools.cs:348
FileLog.Debug("AccessTools.DeclaredIndexer: type is null");
return null;
}
try
{
// Can find multiple indexers without specified parameters, but only one with specified ones
var indexer = parameters is null ?
type.GetProperties(allDeclared).SingleOrDefault(property => property.GetIndexParameters().Length > 0)
: type.GetProperties(allDeclared).FirstOrDefault(property => property.GetIndexParameters().Select(param => param.ParameterType).SequenceEqual(parameters));
if (indexer is null)
FileLog.Debug($"AccessTools.DeclaredIndexer: Could not find indexer for type {type} and parameters {parameters?.Description()}");
return indexer;
}
catch (InvalidOperationException ex)
{
throw new AmbiguousMatchException("Multiple possible indexers were found.", ex);
}
}
/// <summary>Gets the reflection information for the getter method of a directly declared property</summary>
/// <param name="type">The class/type where the property is declared</param>
/// <param name="name">The name of the property (case sensitive)</param>
/// <returns>A method or null when type/name is null or when the property cannot be found</returns>
///
public static MethodInfo DeclaredPropertyGetter(Type type, string name) => DeclaredProperty(type, name)?.GetGetMethod(true);
/// <summary>Gets the reflection information for the getter method of a directly declared property</summary>
/// <param name="typeColonName">The member in the form <c>TypeFullName:MemberName</c>, where TypeFullName matches the form recognized by <a href="https://docs.microsoft.com/en-us/dotnet/api/system.type.gettype">Type.GetType</a> like <c>Some.Namespace.Type</c>.</param>
/// <returns>A method or null when the property cannot be found</returns>
///
public static MethodInfo DeclaredPropertyGetter(string typeColonName) => DeclaredProperty(typeColonName)?.GetGetMethod(true);
/// <summary>Gets the reflection information for the getter method of a directly declared indexer property</summary>
/// <param name="type">The class/type where the indexer property is declared</param>
View on GitHub (pinned to e7872dc170)