pardeike/Harmony · error · ArgumentException
FieldDeclaringType must be T (StructFieldRefAccess instance…
Error message
FieldDeclaringType must be T (StructFieldRefAccess instance type)
What it means
ValidateStructField requires the field's declaring type to exactly equal the struct type T used for StructFieldRefAccess, because the instance you pass is a T and the emitted ref IL assumes the field lives on T. A field inherited from a base class (DeclaringType != T) would compute the wrong address.
Solutions
- Resolve the field on its actual declaring type and pass that type as T
- Use the class-based FieldRefAccess overload when the field is inherited rather than declared on the struct
- Check fieldInfo.DeclaringType == typeof(T) before calling
Example fix
// before var fr = Tools.StructFieldRefAccess<Derived, int>(AccessTools.Field(typeof(Base), "hp")); // after var fr = Tools.FieldRefAccess<Derived, int>(AccessTools.Field(typeof(Base), "hp"));
Defensive patterns
Strategy: validation
Validate before calling
var fi = AccessTools.Field(typeof(T), fieldName);
if (fi != null && fi.DeclaringType != typeof(T)) throw new ArgumentException($"{fieldName} is declared on {fi.DeclaringType}, not {typeof(T)}"); Type guard
bool DeclaredOnStruct<T>(FieldInfo fi) where T : struct => fi?.DeclaringType == typeof(T);
Try / catch
try { var fr = Tools.StructFieldRefAccess<T, F>(fi); }
catch (ArgumentException ex) when (ex.Message.Contains("FieldDeclaringType must be T")) { /* switch to FieldRefAccess with declaring type */ } Prevention
- Match T exactly to fieldInfo.DeclaringType for struct refs
- For inherited fields use class FieldRefAccess instead of the struct variant
- Resolve fields with AccessTools.DeclaredField to get the exact declaring type
When it happens
Trigger: Calling StructFieldRefAccess<T, F> with a field whose DeclaringType is a base class (or different struct) than the struct type argument T.
Common situations: Accessing a field inherited from a parent class through the derived struct/class type; resolving the field via typeof(Base) but using T = derived.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Ambiguous match for HarmonyMethod
- No method found for type=
- No method found for , parameters= , generics=
- No field found for and
- Cannot not find method for type
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/75b1d293f8107f58.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Tools/Tools.cs:145
internal static bool FieldRefNeedsClasscast(Type delegateInstanceType, Type declaringType)
{
var needCastclass = false;
if (delegateInstanceType != declaringType)
{
needCastclass = delegateInstanceType.IsAssignableFrom(declaringType);
if (needCastclass is false && declaringType.IsAssignableFrom(delegateInstanceType) is false)
throw new ArgumentException("FieldDeclaringType must be assignable from or to T (FieldRefAccess instance type) - " +
"\"instanceOfT is FieldDeclaringType\" must be possible");
}
return needCastclass;
}
internal static void ValidateStructField<T, F>(FieldInfo fieldInfo) where T : struct
{
if (fieldInfo.IsStatic)
throw new ArgumentException("Field must not be static");
if (fieldInfo.DeclaringType != typeof(T))
throw new ArgumentException("FieldDeclaringType must be T (StructFieldRefAccess instance type)");
}
}
}
View on GitHub (pinned to e7872dc170)