{"record":{"id":"0f815879dd32b141","repo":"pardeike/Harmony","slug":"multiple-possible-indexers-were-found","errorCode":null,"errorMessage":"Multiple possible indexers were found.","messagePattern":"Multiple possible indexers were found\\.","errorType":"exception","errorClass":"AmbiguousMatchException","httpStatus":null,"severity":"error","filePath":"Harmony/Tools/AccessTools.cs","lineNumber":348,"sourceCode":"\t\t\t\tFileLog.Debug(\"AccessTools.DeclaredIndexer: type is null\");\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\r\n\t\t\ttry\r\n\t\t\t{\r\n\t\t\t\t// Can find multiple indexers without specified parameters, but only one with specified ones\r\n\t\t\t\tvar indexer = parameters is null ?\r\n\t\t\t\t\ttype.GetProperties(allDeclared).SingleOrDefault(property => property.GetIndexParameters().Length > 0)\r\n\t\t\t\t\t: type.GetProperties(allDeclared).FirstOrDefault(property => property.GetIndexParameters().Select(param => param.ParameterType).SequenceEqual(parameters));\r\n\r\n\t\t\t\tif (indexer is null)\r\n\t\t\t\t\tFileLog.Debug($\"AccessTools.DeclaredIndexer: Could not find indexer for type {type} and parameters {parameters?.Description()}\");\r\n\r\n\t\t\t\treturn indexer;\r\n\t\t\t}\r\n\t\t\tcatch (InvalidOperationException ex)\r\n\t\t\t{\r\n\t\t\t\tthrow new AmbiguousMatchException(\"Multiple possible indexers were found.\", ex);\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t/// <summary>Gets the reflection information for the getter method of a directly declared property</summary>\r\n\t\t/// <param name=\"type\">The class/type where the property is declared</param>\r\n\t\t/// <param name=\"name\">The name of the property (case sensitive)</param>\r\n\t\t/// <returns>A method or null when type/name is null or when the property cannot be found</returns>\r\n\t\t///\r\n\t\tpublic static MethodInfo DeclaredPropertyGetter(Type type, string name) => DeclaredProperty(type, name)?.GetGetMethod(true);\r\n\r\n\t\t/// <summary>Gets the reflection information for the getter method of a directly declared property</summary>\r\n\t\t/// <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>\r\n\t\t/// <returns>A method or null when the property cannot be found</returns>\r\n\t\t///\r\n\t\tpublic static MethodInfo DeclaredPropertyGetter(string typeColonName) => DeclaredProperty(typeColonName)?.GetGetMethod(true);\r\n\r\n\t\t/// <summary>Gets the reflection information for the getter method of a directly declared indexer property</summary>\r\n\t\t/// <param name=\"type\">The class/type where the indexer property is declared</param>\r","sourceCodeStart":330,"sourceCodeEnd":366,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Tools/AccessTools.cs#L330-L366","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nvar getter = AccessTools.DeclaredIndexerGetter(typeof(Table)); // multiple indexers\n// after\nvar getter = AccessTools.DeclaredIndexerGetter(typeof(Table), new[] { typeof(string) });","handlingStrategy":"try-catch","validationCode":"var indexers = typeof(T).GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)\n    .Where(p => p.GetIndexParameters().Length > 0).ToArray();\nif (indexers.Length > 1)\n    throw new AmbiguousMatchException($\"{typeof(T)} has {indexers.Length} indexers; pass explicit parameters\");","typeGuard":null,"tryCatchPattern":"try { var getter = AccessTools.DeclaredIndexerGetter(type, paramTypes); }\ncatch (AmbiguousMatchException ex) { /* enumerate type.GetProperties() and pick the indexer manually */ }","preventionTips":["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"],"tags":["csharp","reflection","ambiguous-match","indexer","harmony"],"backgroundTag":"ambiguous-match","analyzedSha":"e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c","analyzedAt":"2026-09-15T22:47:11.550Z","contentChangedAt":"2026-09-15T22:47:11.550Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}