pardeike/Harmony · error · ArgumentException

StaticFieldRefAccess<

Error message

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

What it means

AccessTools.StaticFieldRefAccess<T, F>(fieldInfo) wraps any exception from Tools.StaticFieldRefAccess<F>(fieldInfo)() in an ArgumentException with the FieldInfo in the message. It indicates the given static FieldInfo could not be turned into or invoked as a typed ref accessor for field type F.

Solutions

  1. Inspect InnerException for the root cause.
  2. Assert fieldInfo.IsStatic before calling the API.
  3. Match F exactly to fieldInfo.FieldType.
  4. Re-resolve the FieldInfo with AccessTools.Field(typeof(T), name) instead of passing a stale one.

Example fix

// before
var accessor = AccessTools.StaticFieldRefAccess<Config, int>(someFieldInfo);
// after
var fi = AccessTools.Field(typeof(Config), "cacheSize");
if (fi is { IsStatic: true })
    var accessor = AccessTools.StaticFieldRefAccess<Config, int>(fi);
Defensive patterns

Strategy: validation

Validate before calling

if (fieldInfo is null || !fieldInfo.IsStatic || fieldInfo.FieldType != typeof(F))
    throw new InvalidOperationException("FieldInfo must be a static field of type " + typeof(F));

Type guard

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

Try / catch

try { var r = AccessTools.StaticFieldRefAccess<T, F>(fieldInfo)(); }
catch (ArgumentException ex) { logger.Warn(ex.InnerException, "ref access failed for {0}", fieldInfo); }

Prevention

When it happens

Trigger: Calling AccessTools.StaticFieldRefAccess<T, F>(AccessTools.Field(typeof(T), name)) where fieldInfo is not static, F does not match the field's declared type, or the runtime ref-accessor creation/invocation throws.

Common situations: Passing an instance field's FieldInfo by mistake, generic F mismatch after a target library update changed the field type, or caching an accessor for a field that was removed.

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

Appendix: source

Thrown at Harmony/Tools/AccessTools.cs:1721

		/// </typeparam>
		/// <param name="fieldInfo">The field</param>
		/// <returns>A readable/assignable reference to the field</returns>
		/// <remarks>
		/// The type parameter <typeparamref name="T"/> is only used in exception messaging and to distinguish between this method overload
		/// and the <see cref="StaticFieldRefAccess{F}(FieldInfo)"/> overload (which returns a <see cref="FieldRef{F}"/> rather than a reference).
		/// </remarks>
		///
		public static ref F StaticFieldRefAccess<T, F>(FieldInfo fieldInfo)
		{
			if (fieldInfo is null)
				throw new ArgumentNullException(nameof(fieldInfo));
			try
			{
				return ref Tools.StaticFieldRefAccess<F>(fieldInfo)();
			}
			catch (Exception ex)
			{
				throw new ArgumentException($"StaticFieldRefAccess<{typeof(T)}, {typeof(F)}> for {fieldInfo} caused an exception", ex);
			}
		}

		/// <summary>Creates a static field reference delegate</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>
		/// <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
			{

View on GitHub (pinned to e7872dc170)