pardeike/Harmony · error · ArgumentException
Field must be static
Error message
Field must be static
What it means
Tools.StaticFieldRefAccess<F> builds a delegate that returns a ref to a static field, which requires the FieldInfo to have IsStatic set. If a non-static (instance) field is passed, ArgumentException("Field must be static") is thrown because there is no instance context in which the ref could be meaningful.
Solutions
- Pass a static field: resolve with BindingFlags.Static, e.g. typeof(T).GetField("name", BindingFlags.NonPublic | BindingFlags.Static)
- Verify fieldInfo.IsStatic before calling and route instance fields to the instance FieldRefAccess<T,F> overload (which takes the instance/ref target)
- If the field became instance-only after a target update, switch to the instance-based ref API
Example fix
// before
var f = typeof(C).GetField("counter", BindingFlags.NonPublic | BindingFlags.Instance);
var rf = Tools.StaticFieldRefAccess<int>(f); // instance field => throws
// after
var f = typeof(C).GetField("counter", BindingFlags.NonPublic | BindingFlags.Static);
var rf = Tools.StaticFieldRefAccess<int>(f); Defensive patterns
Strategy: validation
Validate before calling
var f = typeof(T).GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);
if (f is null || !f.IsStatic) throw new InvalidOperationException($"'{name}' is not a static field"); Type guard
static bool IsStaticField(FieldInfo f) => f?.IsStatic == true;
Try / catch
try { rf = Tools.StaticFieldRefAccess<int>(f); }
catch (ArgumentException) { /* f is an instance field: use FieldRefAccess<T, int> with the instance */ } Prevention
- Always include BindingFlags.Static when resolving fields for StaticFieldRefAccess
- Check fieldInfo.IsStatic before calling and route to the instance overload otherwise
- Watch for static↔instance changes in target-library updates; verify with a smoke test at patch load time
When it happens
Trigger: Calling StaticFieldRefAccess<F>(fieldInfo) with an instance field's FieldInfo — commonly obtained via GetField with only NonPublic|Instance bindings, or from iterating DeclaringType.GetFields without filtering IsStatic.
Common situations: Developer picked the instance-field overload of a same-named field pair; the field was changed from static to instance (or vice versa) in a target-library update; generic tooling that resolves fields by name without checking BindingFlags.
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
- Field must not be static
- StaticFieldRefAccess<
- StaticFieldRefAccess<
- StaticFieldRefAccess<
- Invalid Expression. Expression should consist of a Method…
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/b9cb818bc4a3a290.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Tools/Tools.cs:104
internal static StructFieldRef<T, F> StructFieldRefAccess<T, F>(FieldInfo fieldInfo) where T : struct
{
ValidateFieldType<F>(fieldInfo);
var dm = new DynamicMethodDefinition($"__refget_{typeof(T).Name}_struct_fi_{fieldInfo.Name}",
typeof(F).MakeByRefType(), [typeof(T).MakeByRefType()]);
var il = dm.GetILGenerator();
il.Emit(OpCodes.Ldarg_0);
il.Emit(OpCodes.Ldflda, fieldInfo);
il.Emit(OpCodes.Ret);
return dm.Generate().CreateDelegate<StructFieldRef<T, F>>();
}
internal static FieldRef<F> StaticFieldRefAccess<F>(FieldInfo fieldInfo)
{
if (fieldInfo.IsStatic is false)
throw new ArgumentException("Field must be static");
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)
View on GitHub (pinned to e7872dc170)