{"record":{"id":"c9271f8b8ee15c40","repo":"pardeike/Harmony","slug":"patch-method-patch-fulldescription-must-be-static","errorCode":null,"errorMessage":"Patch method {patch.FullDescription()} must be static","messagePattern":"Patch method (.+?) must be static","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Harmony/Internal/PatchModels.cs","lineNumber":105,"sourceCode":"\t\t\tHarmonyPatchType.InnerPostfix\r\n\t\t];\r\n\r\n\t\tinternal HarmonyMethod info;\r\n\t\tinternal HarmonyPatchType? type;\r\n\r\n\t\tinternal static AttributePatch Create(MethodInfo patch)\r\n\t\t{\r\n\t\t\tif (patch is null)\r\n\t\t\t\tthrow new NullReferenceException(\"Patch method cannot be null\");\r\n\r\n\t\t\tvar allAttributes = patch.GetCustomAttributes(true);\r\n\t\t\tvar methodName = patch.Name;\r\n\t\t\tvar type = GetPatchType(methodName, allAttributes);\r\n\t\t\tif (type is null)\r\n\t\t\t\treturn null;\r\n\r\n\t\t\tif (type != HarmonyPatchType.ReversePatch && patch.IsStatic is false)\r\n\t\t\t\tthrow new ArgumentException(\"Patch method \" + patch.FullDescription() + \" must be static\");\r\n\r\n\t\t\tvar list = allAttributes\r\n\t\t\t\t.Where(attr => attr.GetType().BaseType.FullName == PatchTools.harmonyAttributeFullName)\r\n\t\t\t\t.Select(attr =>\r\n\t\t\t\t{\r\n\t\t\t\t\tvar f_info = AccessTools.Field(attr.GetType(), nameof(HarmonyAttribute.info));\r\n\t\t\t\t\treturn f_info.GetValue(attr);\r\n\t\t\t\t})\r\n\t\t\t\t.Select(AccessTools.MakeDeepCopy<HarmonyMethod>)\r\n\t\t\t\t.ToList();\r\n\t\t\tvar info = HarmonyMethod.Merge(list);\r\n\t\t\tinfo.method = patch;\r\n\r\n\t\t\treturn new AttributePatch() { info = info, type = type };\r\n\t\t}\r\n\r\n\t\tstatic HarmonyPatchType? GetPatchType(string methodName, object[] allAttributes)\r\n\t\t{\r","sourceCodeStart":87,"sourceCodeEnd":123,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Internal/PatchModels.cs#L87-L123","documentation":"Harmony patch methods (prefix, postfix, finalizer, transpiler) must be static; only ReversePatch stand-ins may be instance methods. AttributePatch.Create throws this ArgumentException when the annotated patch method's patch type is not ReversePatch and the method is not static.","triggerScenarios":"Annotating an instance method with [HarmonyPrefix]/[HarmonyPostfix]/[HarmonyFinalizer]/[HarmonyTranspiler] and running PatchAll/PatchClassProcessor over the class.","commonSituations":"Converting older patches to instance-style for state, accidentally attaching attributes to instance helpers, or moving a patch method into a class without keeping it static.","solutions":["Mark the patch method static (and keep parameters injected via Harmony's special names instead of instance state).","If you need per-instance state, use static fields, __instance/__0 injection, or a state object parameter.","If the method is genuinely a ReversePatch stand-in, ensure GetPatchType resolves it as ReversePatch (attribute/naming) so the static check is bypassed."],"exampleFix":"// before\nclass P {\n  [HarmonyPrefix]\n  void Prefix(int x) { } // instance method\n}\n\n// after\nclass P {\n  [HarmonyPrefix]\n  static void Prefix(int x) { }","handlingStrategy":"validation","validationCode":"foreach (var m in typeof(MyPatches).GetMethods())\n    if (m.GetCustomAttributes(true).Any(a => a.GetType().Name.StartsWith(\"Harmony\")) && !m.IsStatic)\n        throw new InvalidOperationException($\"{m.Name} must be static\");","typeGuard":"static bool IsValidPatchMethod(MethodInfo m) =>\n    m.IsStatic || m.GetCustomAttributes(true).Any(a => a is HarmonyAttribute h && h.info.patchType == HarmonyPatchType.ReversePatch);","tryCatchPattern":"try { harmony.PatchAll(typeof(MyPatches)); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"must be static\"))\n{ Logger.Error($\"Non-static patch method: {ex.Message}\"); }","preventionTips":["Always declare prefix/postfix/finalizer/transpiler methods static.","Use injected parameters (__instance, __0, __result) instead of instance fields for state.","Add a startup reflection check that all [Harmony*]-annotated methods in your assembly are static."],"tags":["harmony","patch-annotation","static-required"],"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"}