pardeike/Harmony · error · ArgumentException

StructFieldRefAccess<

Error message

StructFieldRefAccess<{typeof(T)}, {typeof(F)}> for {instance}, {fieldInfo} caused an exception

What it means

Catch-all wrapper in the instance-taking StructFieldRefAccess<T,F>(fieldInfo)(ref instance): any failure during validation or delegate creation/invocation is rethrown as an ArgumentException naming T, F, the instance and the FieldInfo, with the cause as InnerException.

Solutions

  1. Check ex.InnerException for the actual failure
  2. Re-validate fieldInfo against typeof(T) and typeof(F) at the call site
  3. Do not reuse cached field delegates across different struct types
  4. Pin the expected target assembly version and re-verify FieldInfo after updates

Example fix

// before
ref var v = ref AccessTools.StructFieldRefAccess<OtherStruct, int>(fi)(ref instance); // wrong struct type
// after
ref var v = ref AccessTools.StructFieldRefAccess<MyStruct, int>(fi)(ref instance);
Defensive patterns

Strategy: validation

Validate before calling

if (fi.DeclaringType != typeof(T) || fi.IsStatic || fi.FieldType != typeof(F)) throw new ArgumentException("invalid struct field ref arguments");

Type guard

static bool MatchesStruct<T>(FieldInfo fi) where T : struct => fi.DeclaringType == typeof(T) && !fi.IsStatic && fi.FieldType == typeof(F);

Try / catch

try { ref var v = ref AccessTools.StructFieldRefAccess<T, F>(fi)(ref instance); }
catch (ArgumentException ex) { throw new InvalidOperationException("StructFieldRefAccess failed", ex.InnerException ?? ex); }

Prevention

When it happens

Trigger: Same conditions as error 88 (wrong declaring type, static field, F type mismatch) raised from the overload that applies the ref delegate to a specific struct instance.

Common situations: Using a cached delegate built for one struct type against another struct's instance; target library type changed from class to struct (or vice versa) across versions.

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/b3f5718bc76ad507. Report an issue: GitHub.

Appendix: source

Thrown at Harmony/Tools/AccessTools.cs:1635

		/// <para>
		/// This method is meant for one-off access to a field's value for a single instance and where the field has already been obtained.
		/// If you need to access a field's value for potentially multiple instances, use <see cref="StructFieldRefAccess{T, F}(FieldInfo)"/> instead.
		/// <c>StructFieldRefAccess&lt;T, F&gt;(ref instance, fieldInfo)</c> is functionally equivalent to <c>StructFieldRefAccess&lt;T, F&gt;(fieldInfo)(ref instance)</c>.
		/// </para>
		/// </remarks>
		///
		public static ref F StructFieldRefAccess<T, F>(ref T instance, FieldInfo fieldInfo) where T : struct
		{
			if (fieldInfo is null)
				throw new ArgumentNullException(nameof(fieldInfo));
			try
			{
				Tools.ValidateStructField<T, F>(fieldInfo);
				return ref Tools.StructFieldRefAccess<T, F>(fieldInfo)(ref instance);
			}
			catch (Exception ex)
			{
				throw new ArgumentException($"StructFieldRefAccess<{typeof(T)}, {typeof(F)}> for {instance}, {fieldInfo} caused an exception", ex);
			}
		}

		/// <summary>A readable/assignable reference delegate to a static field</summary>
		/// <typeparam name="F">
		/// The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type),
		/// a type that <see cref="Type.IsAssignableFrom(Type)">is assignable from</see> that type; or if the field's type is an enum type,
		/// either that type or the underlying integral type of that enum type
		/// </typeparam>
		/// <returns>A readable/assignable reference to the field</returns>
		///
		public delegate ref F FieldRef<F>();

		/// <summary>Creates a static field reference</summary>
		/// <typeparam name="T">The type (can be class or struct) the field is defined in</typeparam>
		/// <typeparam name="F">
		/// The type of the field; or if the field's type is a reference type (a class or interface, NOT a struct or other value type),
		/// a type that <see cref="Type.IsAssignableFrom(Type)">is assignable from</see> that type; or if the field's type is an enum type,

View on GitHub (pinned to e7872dc170)