{"record":{"id":"b9cb818bc4a3a290","repo":"pardeike/Harmony","slug":"field-must-be-static","errorCode":null,"errorMessage":"Field must be static","messagePattern":"Field must be static","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Harmony/Tools/Tools.cs","lineNumber":104,"sourceCode":"\t\tinternal static StructFieldRef<T, F> StructFieldRefAccess<T, F>(FieldInfo fieldInfo) where T : struct\r\n\t\t{\r\n\t\t\tValidateFieldType<F>(fieldInfo);\r\n\r\n\t\t\tvar dm = new DynamicMethodDefinition($\"__refget_{typeof(T).Name}_struct_fi_{fieldInfo.Name}\",\r\n\t\t\t\ttypeof(F).MakeByRefType(), [typeof(T).MakeByRefType()]);\r\n\r\n\t\t\tvar il = dm.GetILGenerator();\r\n\t\t\til.Emit(OpCodes.Ldarg_0);\r\n\t\t\til.Emit(OpCodes.Ldflda, fieldInfo);\r\n\t\t\til.Emit(OpCodes.Ret);\r\n\r\n\t\t\treturn dm.Generate().CreateDelegate<StructFieldRef<T, F>>();\r\n\t\t}\r\n\r\n\t\tinternal static FieldRef<F> StaticFieldRefAccess<F>(FieldInfo fieldInfo)\r\n\t\t{\r\n\t\t\tif (fieldInfo.IsStatic is false)\r\n\t\t\t\tthrow new ArgumentException(\"Field must be static\");\r\n\t\t\tValidateFieldType<F>(fieldInfo);\r\n\r\n\t\t\tvar dm = new DynamicMethodDefinition($\"__refget_{fieldInfo.DeclaringType?.Name ?? \"null\"}_static_fi_{fieldInfo.Name}\",\r\n\t\t\t\ttypeof(F).MakeByRefType(), []);\r\n\r\n\t\t\tvar il = dm.GetILGenerator();\r\n\t\t\til.Emit(OpCodes.Ldsflda, fieldInfo);\r\n\t\t\til.Emit(OpCodes.Ret);\r\n\r\n\t\t\treturn dm.Generate().CreateDelegate<FieldRef<F>>();\r\n\t\t}\r\n\r\n\t\tinternal static FieldInfo GetInstanceField(Type type, string fieldName)\r\n\t\t{\r\n\t\t\tvar fieldInfo = Field(type, fieldName);\r\n\t\t\tif (fieldInfo is null)\r\n\t\t\t\tthrow new MissingFieldException(type.Name, fieldName);\r\n\t\t\tif (fieldInfo.IsStatic)\r","sourceCodeStart":86,"sourceCodeEnd":122,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Tools/Tools.cs#L86-L122","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nvar f = typeof(C).GetField(\"counter\", BindingFlags.NonPublic | BindingFlags.Instance);\nvar rf = Tools.StaticFieldRefAccess<int>(f); // instance field => throws\n// after\nvar f = typeof(C).GetField(\"counter\", BindingFlags.NonPublic | BindingFlags.Static);\nvar rf = Tools.StaticFieldRefAccess<int>(f);","handlingStrategy":"validation","validationCode":"var f = typeof(T).GetField(name, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static);\nif (f is null || !f.IsStatic) throw new InvalidOperationException($\"'{name}' is not a static field\");","typeGuard":"static bool IsStaticField(FieldInfo f) => f?.IsStatic == true;","tryCatchPattern":"try { rf = Tools.StaticFieldRefAccess<int>(f); }\ncatch (ArgumentException) { /* f is an instance field: use FieldRefAccess<T, int> with the instance */ }","preventionTips":["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"],"tags":["argument-exception","static-field","reflection","field-ref"],"backgroundTag":"invalid-argument-value","analyzedSha":"e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c","analyzedAt":"2026-09-15T22:47:11.550Z","contentChangedAt":"2026-09-15T22:47:11.550Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}