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

  1. Pass an explicit parameters array that uniquely identifies the indexer you want
  2. Disambiguate manually: get the property via type.GetProperties() and pick by indexer parameter type, then use its GetMethod/SetMethod
  3. 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

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


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)