pardeike/Harmony · error · ArgumentException

StaticFieldRefAccess<

Error message

StaticFieldRefAccess<{typeof(F)}> for {fieldInfo} caused an exception

What it means

AccessTools.StaticFieldRefAccess<F>(fieldInfo) wraps any exception from creating the delegate-returning ref accessor in an ArgumentException. This overload returns the accessor delegate itself, so failures here mean the FieldInfo could not be compiled into a ref getter.

Solutions

  1. Check InnerException for the actual failure.
  2. Verify fieldInfo is non-null and IsStatic.
  3. Ensure F equals fieldInfo.FieldType.
  4. Resolve the FieldInfo via AccessTools.Field on the correct declaring type.

Example fix

// before
var getter = AccessTools.StaticFieldRefAccess<float>(instanceFieldInfo);
// after
var fi = AccessTools.Field(typeof(Physics), "gravity");
var getter = AccessTools.StaticFieldRefAccess<float>(fi); // gravity is static float
Defensive patterns

Strategy: validation

Validate before calling

if (fieldInfo is null || !fieldInfo.IsStatic || fieldInfo.FieldType != typeof(F))
    return null; // skip creating accessor
var getter = AccessTools.StaticFieldRefAccess<F>(fieldInfo);

Type guard

bool CanMakeRefAccessor<F>(FieldInfo fi) => fi is { IsStatic: true } && fi.FieldType == typeof(F);

Try / catch

try { var getter = AccessTools.StaticFieldRefAccess<F>(fieldInfo); }
catch (ArgumentException ex) { logger.Warn(ex.InnerException, "cannot build accessor for {0}", fieldInfo); }

Prevention

When it happens

Trigger: Calling AccessTools.StaticFieldRefAccess<F>(fieldInfo) with a non-static FieldInfo, a FieldInfo whose type differs from F, or an otherwise unusable FieldInfo (e.g. from a dynamic/collected type).

Common situations: Mixing up the delegate-returning overload with the ref-returning one, passing null or a FieldInfo resolved from a different declaring type, F not matching after a target update.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15). Data as JSON: /api/errors/046b4e382f6f6288. Report an issue: GitHub.

Appendix: source

Thrown at Harmony/Tools/AccessTools.cs:1744

		/// <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>
		/// <param name="fieldInfo">The field</param>
		/// <returns>A readable/assignable <see cref="FieldRef{F}"/> delegate</returns>
		///
		public static FieldRef<F> StaticFieldRefAccess<F>(FieldInfo fieldInfo)
		{
			if (fieldInfo is null)
				throw new ArgumentNullException(nameof(fieldInfo));
			try
			{
				return Tools.StaticFieldRefAccess<F>(fieldInfo);
			}
			catch (Exception ex)
			{
				throw new ArgumentException($"StaticFieldRefAccess<{typeof(F)}> for {fieldInfo} caused an exception", ex);
			}
		}

#pragma warning disable CS1591
		[Obsolete("This overload only exists for runtime backwards compatibility and will be removed in Harmony 3. Use MethodDelegate(MethodInfo, object, bool, Type[]) instead")]
		[EditorBrowsable(EditorBrowsableState.Never)]
		public static DelegateType MethodDelegate<DelegateType>(MethodInfo method, object instance, bool virtualCall) where DelegateType : Delegate
			 => MethodDelegate<DelegateType>(method, instance, virtualCall, null);
#pragma warning restore CS1591

		/// <summary>Creates a delegate to a given method</summary>
		/// <typeparam name="DelegateType">The delegate Type</typeparam>
		/// <param name="method">The method to create a delegate from.</param>
		/// <param name="instance">
		/// Only applies for instance methods. If <c>null</c> (default), returned delegate is an open (a.k.a. unbound) instance delegate
		/// where an instance is supplied as the first argument to the delegate invocation; else, delegate is a closed (a.k.a. bound)
		/// instance delegate where the delegate invocation always applies to the given <paramref name="instance"/>.
		/// </param>

View on GitHub (pinned to e7872dc170)