pardeike/Harmony · error · ArgumentException

Field must not be static

Error message

Field must not be static

What it means

Harmony's Tools.GetInstanceField resolves a field by name and refuses to return static fields because the caller asked for an instance field via reflection on a specific instance type. Static fields live on the type, not the instance, so returning one here would be a caller bug or a wrong fieldName/type pair.

Solutions

  1. Make the field non-static in the target type if an instance field is genuinely intended
  2. Use a static-field accessor (e.g. AccessTools.Field + fieldInfo.GetValue(null), or a static field ref helper) instead of GetInstanceField
  3. Verify the field's modifiers with AccessTools.DeclaredField/fieldInfo.IsStatic before calling

Example fix

// before
var fi = Tools.GetInstanceField(typeof(Player), "instanceCount"); // instanceCount is static
// after
var fi = typeof(Player).GetField("instanceCount", BindingFlags.Static | BindingFlags.NonPublic);
Defensive patterns

Strategy: validation

Validate before calling

var fi = AccessTools.Field(type, fieldName);
if (fi == null) throw new MissingFieldException(type.Name, fieldName);
if (fi.IsStatic) throw new ArgumentException($"{type.Name}.{fieldName} is static; use a static field accessor");

Type guard

bool IsInstanceField(Type t, string name) =>
    t.GetField(name, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic) is { IsStatic: false };

Try / catch

try { var fi = Tools.GetInstanceField(type, fieldName); }
catch (ArgumentException ex) when (ex.Message == "Field must not be static") { /* fall back to static access */ }
catch (MissingFieldException) { /* field doesn't exist */ }

Prevention

When it happens

Trigger: Calling Tools.GetInstanceField(type, fieldName) (directly or via AccessTools/field-ref helpers) where fieldName names a static field on the given type instead of an instance field.

Common situations: Target class refactored an instance field into a static one; copy-pasting a field name without checking its modifiers; using the helper to fetch constants or cached/singleton fields that are static.

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

Appendix: source

Thrown at Harmony/Tools/Tools.cs:123

			ValidateFieldType<F>(fieldInfo);

			var dm = new DynamicMethodDefinition($"__refget_{fieldInfo.DeclaringType?.Name ?? "null"}_static_fi_{fieldInfo.Name}",
				typeof(F).MakeByRefType(), []);

			var il = dm.GetILGenerator();
			il.Emit(OpCodes.Ldsflda, fieldInfo);
			il.Emit(OpCodes.Ret);

			return dm.Generate().CreateDelegate<FieldRef<F>>();
		}

		internal static FieldInfo GetInstanceField(Type type, string fieldName)
		{
			var fieldInfo = Field(type, fieldName);
			if (fieldInfo is null)
				throw new MissingFieldException(type.Name, fieldName);
			if (fieldInfo.IsStatic)
				throw new ArgumentException("Field must not be static");
			return fieldInfo;
		}

		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
		{

View on GitHub (pinned to e7872dc170)