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

  1. Resolve the field on its actual declaring type and pass that type as T
  2. Use the class-based FieldRefAccess overload when the field is inherited rather than declared on the struct
  3. 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

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


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)