pardeike/Harmony · error · MissingMemberException
; available fields: ; available properties
Error message
{string.Join(",", names)}; available fields: {fields}; available properties: {properties} What it means
AccessTools.ThrowMissingMemberException throws MissingMemberException listing the requested names plus all fields and properties actually available on the type. It is Harmony's helper for 'none of these members exist' situations, designed to make diagnosing typos and renamed members easy.
Solutions
- Read the message: pick the correct name from the listed available fields/properties.
- Re-resolve members after a target update by inspecting the type with AccessTools.GetFieldNames/GetPropertyNames.
- Search base types with AccessTools.GetFieldDescendants or flatten inherited members via AccessTools.GetDeclaredFields(type, includeBaseType: true).
- Guard resolution with AccessTools.Field/Property null checks before use.
Example fix
// before AccessTools.Method(typeof(Player), "GetHelth"); // after AccessTools.Method(typeof(Player), "GetHealth"); // message listed 'GetHealth' among available members
Defensive patterns
Strategy: validation
Validate before calling
var fi = AccessTools.Field(type, name) ?? AccessTools.Property(type, name);
if (fi is null)
{
foreach (var candidate in AccessTools.GetFieldNames(type).Concat(AccessTools.GetPropertyNames(type)))
Console.WriteLine(candidate); // pick correct spelling
} Type guard
bool MemberExists(Type t, string n) => AccessTools.Field(t, n) is not null || AccessTools.Property(t, n) is not null;
Try / catch
try { AccessTools.X(type, names); }
catch (MissingMemberException ex) { /* parse 'available fields/properties' list from ex.Message to find correct name */ } Prevention
- Use nameof(...) for member names instead of string literals.
- After target updates, dump available names via AccessTools.GetFieldNames/GetPropertyNames.
- Null-check AccessTools.Field/Property results before use.
When it happens
Trigger: Explicitly calling AccessTools.ThrowMissingMemberException(type, names), or indirectly via AccessTools APIs that resolve one of several member names (e.g. AccessTools.DeclaredMethod/Property variants taking name arrays) when no requested member exists on the type.
Common situations: Target library/game updated and renamed members; typos in member names; looking for a member on a base class where only the derived class has it; confusing a property with a field.
Understand the failure class
Background: Record Not Found Errors: "not found", RecordNotFound, and "was not found" — what they mean and how to fix them — this error's family across 28 libraries.
Related errors
- The type must declare an empty constructor (the constructor…
- Value cannot be null. (Parameter 'fromMethod')
- Value cannot be null. (Parameter 'method')
- Value cannot be null. (Parameter 'config.original')
- Undefined target method for patch method
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/9cd660c7070fc89e.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Tools/AccessTools.cs:2066
public static bool IsNetFrameworkRuntime { get; } =
Type.GetType("System.Runtime.InteropServices.RuntimeInformation", false)?.GetProperty("FrameworkDescription")
.GetValue(null, null).ToString().StartsWith(".NET Framework") ?? IsMonoRuntime is false;
/// <summary>True if the current runtime is .NET Core, false otherwise (Mono or .NET Framework)</summary>
///
public static bool IsNetCoreRuntime { get; } =
Type.GetType("System.Runtime.InteropServices.RuntimeInformation", false)?.GetProperty("FrameworkDescription")
.GetValue(null, null).ToString().StartsWith(".NET Core") ?? false;
/// <summary>Throws a missing member runtime exception</summary>
/// <param name="type">The type that is involved</param>
/// <param name="names">A list of names</param>
///
public static void ThrowMissingMemberException(Type type, params string[] names)
{
var fields = string.Join(",", [.. GetFieldNames(type)]);
var properties = string.Join(",", [.. GetPropertyNames(type)]);
throw new MissingMemberException($"{string.Join(",", names)}; available fields: {fields}; available properties: {properties}");
}
/// <summary>Gets default value for a specific type</summary>
/// <param name="type">The class/type</param>
/// <returns>The default value</returns>
///
public static object GetDefaultValue(Type type)
{
if (type is null)
{
FileLog.Debug("AccessTools.GetDefaultValue: type is null");
return null;
}
if (type == typeof(void))
return null;
if (type.IsValueType)
return Activator.CreateInstance(type);
return null;
View on GitHub (pinned to e7872dc170)