{"record":{"id":"7fa2a28432236f22","repo":"pardeike/Harmony","slug":"you-can-only-patch-implemented-methods-constructors-patch","errorCode":null,"errorMessage":"You can only patch implemented methods/constructors. Patch the declared method {declaredMember.FullDescription()} instead.","messagePattern":"You can only patch implemented methods/constructors\\. Patch the declared method (.+?) instead\\.","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Harmony/Public/PatchProcessor.cs","lineNumber":177,"sourceCode":"\t\t{\r\n\t\t\tlock (locker)\r\n\t\t\t{\r\n\t\t\t\treturn HarmonySharedState.GetPatchedMethods();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\t/// <summary>Applies all registered patches</summary>\r\n\t\t/// <returns>The generated replacement method</returns>\r\n\t\t///\r\n\t\tpublic MethodInfo Patch()\r\n\t\t{\r\n\t\t\tif (original is null)\r\n\t\t\t\tthrow new NullReferenceException($\"Null method for {instance.Id}\");\r\n\r\n\t\t\tif (original.IsDeclaredMember() is false)\r\n\t\t\t{\r\n\t\t\t\tvar declaredMember = original.GetDeclaredMember();\r\n\t\t\t\tthrow new ArgumentException($\"You can only patch implemented methods/constructors. Patch the declared method {declaredMember.FullDescription()} instead.\");\r\n\t\t\t}\r\n\r\n\t\t\tlock (locker)\r\n\t\t\t{\r\n\t\t\t\tvar patchInfo = HarmonySharedState.GetPatchInfo(original) ?? new PatchInfo();\r\n\r\n\t\t\t\tpatchInfo.AddPrefixes(instance.Id, prefix);\r\n\t\t\t\tpatchInfo.AddPostfixes(instance.Id, postfix);\r\n\t\t\t\tpatchInfo.AddTranspilers(instance.Id, transpiler);\r\n\t\t\t\tpatchInfo.AddFinalizers(instance.Id, finalizer);\r\n\t\t\t\tpatchInfo.AddInnerPrefixes(instance.Id, innerprefix);\r\n\t\t\t\tpatchInfo.AddInnerPostfixes(instance.Id, innerpostfix);\r\n\r\n\t\t\t\tvar replacement = PatchFunctions.UpdateWrapper(original, patchInfo);\r\n\t\t\t\tHarmonySharedState.UpdatePatchInfo(original, replacement, patchInfo);\r\n\t\t\t\treturn replacement;\r\n\t\t\t}\r\n\t\t}\r","sourceCodeStart":159,"sourceCodeEnd":195,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Public/PatchProcessor.cs#L159-L195","documentation":"Harmony can only patch the method that actually declares a body. If the MethodInfo passed to Patch() is an abstract method, interface method, or otherwise non-implemented member, Harmony resolves the declaring definition and throws an ArgumentException telling you to patch that declared method instead.","triggerScenarios":"Calling Patch() with a MethodInfo obtained from a derived type, a base-type reference, a MakeGenericMethod result, or an interface method where IsDeclaredMember() is false — e.g. patching typeof(IFoo).GetMethod(\"Bar\") or patching an abstract base method.","commonSituations":"Developers patch methods accessed through interface types or generic base classes; patching virtual methods via a base-class MethodInfo obtained from an interface lookup; targets refactored from concrete to abstract in a library update.","solutions":["Patch the concrete implemented method: look the method up on the concrete type that provides the body","Use Harmony's GetDeclaredMember() result from the error message as the patch target","If the target is abstract/interface-only, patch a concrete derived implementation or use a different hook point"],"exampleFix":"// before\nvar original = typeof(IPlayer).GetMethod(\"Update\");\nharmony.Patch(original, prefix: prefixMethod);\n// after\nvar original = typeof(Player).GetMethod(\"Update\"); // concrete implementing type\nharmony.Patch(original, prefix: prefixMethod);","handlingStrategy":"validation","validationCode":"if (original is not null && !original.IsDeclaredMember())\n{\n    var declared = original.GetDeclaredMember();\n    original = declared as MethodInfo ?? throw new InvalidOperationException($\"Patch the declared method {declared.FullDescription()} instead\");\n}","typeGuard":null,"tryCatchPattern":"try { harmony.Patch(original, prefix: prefix); }\ncatch (ArgumentException ex) when (ex.Message.Contains(\"implemented methods/constructors\")) { /* retarget to concrete type */ }","preventionTips":["Look patch targets up on concrete implementing types, not interfaces or abstract bases","Avoid patching methods obtained through generic interface dispatch","Check original.IsAbstract / !original.HasMethodBody() before patching"],"tags":["csharp","reflection","abstract-method","harmony"],"backgroundTag":"unsupported-operation","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"}