{"record":{"id":"9988bf0ea93917f1","repo":"pardeike/Harmony","slug":"using-patchtools-harmonypatchallfullname-requires-an","errorCode":null,"errorMessage":"Using {PatchTools.harmonyPatchAllFullName} requires an additional attribute for specifying the Class/Type","messagePattern":"Using (.+?) requires an additional attribute for specifying the Class/Type","errorType":"exception","errorClass":"ArgumentException","httpStatus":null,"severity":"error","filePath":"Harmony/Public/PatchClassProcessor.cs","lineNumber":251,"sourceCode":"\t\t\t\tjob.postfixes.Do(patch => patchInfo.RemovePatch(patch.method));\r\n\t\t\t\tjob.prefixes.Do(patch => patchInfo.RemovePatch(patch.method));\r\n\t\t\t}\r\n\t\t\tjob.transpilers.Do(patch => patchInfo.RemovePatch(patch.method));\r\n\t\t\tif (hasBody)\r\n\t\t\t\tjob.finalizers.Do(patch => patchInfo.RemovePatch(patch.method));\r\n\r\n\t\t\tvar replacement = PatchFunctions.UpdateWrapper(job.original, patchInfo);\r\n\t\t\tHarmonySharedState.UpdatePatchInfo(job.original, replacement, patchInfo);\r\n\t\t}\r\n\r\n\t\tList<MethodBase> GetBulkMethods()\r\n\t\t{\r\n\t\t\tvar isPatchAll = containerType.GetCustomAttributes(true).Any(a => a.GetType().FullName == PatchTools.harmonyPatchAllFullName);\r\n\t\t\tif (isPatchAll)\r\n\t\t\t{\r\n\t\t\t\tvar type = containerAttributes.declaringType;\r\n\t\t\t\tif (type is null)\r\n\t\t\t\t\tthrow new ArgumentException($\"Using {PatchTools.harmonyPatchAllFullName} requires an additional attribute for specifying the Class/Type\");\r\n\r\n\t\t\t\tvar list = new List<MethodBase>();\r\n\t\t\t\tlist.AddRange(AccessTools.GetDeclaredConstructors(type).Cast<MethodBase>());\r\n\t\t\t\tlist.AddRange(AccessTools.GetDeclaredMethods(type).Cast<MethodBase>());\r\n\t\t\t\tvar props = AccessTools.GetDeclaredProperties(type);\r\n\t\t\t\tlist.AddRange(props.Select(prop => prop.GetGetMethod(true)).Where(method => method is not null).Cast<MethodBase>());\r\n\t\t\t\tlist.AddRange(props.Select(prop => prop.GetSetMethod(true)).Where(method => method is not null).Cast<MethodBase>());\r\n\t\t\t\treturn list;\r\n\t\t\t}\r\n\r\n\t\t\tvar result = new List<MethodBase>();\r\n\r\n\t\t\tvar targetMethods = RunMethod<HarmonyTargetMethods, IEnumerable<MethodBase>>(null, null);\r\n\t\t\tif (targetMethods is object)\r\n\t\t\t{\r\n\t\t\t\tstring error = null;\r\n\t\t\t\tresult = [.. targetMethods];\r\n\t\t\t\tif (result is null)\r","sourceCodeStart":233,"sourceCodeEnd":269,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Public/PatchClassProcessor.cs#L233-L269","documentation":"[HarmonyPatchAll] tells Harmony to patch many methods at once, but it does not say on which class those methods live. When the patch class does not also declare a declaring type (via [HarmonyPatch(typeof(...))] on the class or Harmony.CreateAndPatchAll(type, type)), GetBulkMethods throws.","triggerScenarios":"Calling PatchAll on a class marked only with [HarmonyPatchAll] without any [HarmonyPatch(typeof(X))] class-level attribute, or Harmony.PatchAll() where the container type has no declaring type attribute.","commonSituations":"Copy-pasting a [HarmonyPatchAll] class and dropping the class-level [HarmonyPatch(typeof(...))] line; writing patch classes with only method-level attributes plus HarmonyPatchAll.","solutions":["Add a class-level attribute specifying the target type: [HarmonyPatch(typeof(TargetClass))] alongside [HarmonyPatchAll]","Or call Harmony.CreateAndPatchAll(typeof(YourPatchClass), \"id\") so the declaring type is explicit","Or drop [HarmonyPatchAll] and specify each target with per-method attributes"],"exampleFix":"// before\n[HarmonyPatchAll]\nclass Patches { static void Postfix() { } }\n// after\n[HarmonyPatchAll]\n[HarmonyPatch(typeof(TargetClass))]\nclass Patches { static void Postfix() { } }","handlingStrategy":"validation","validationCode":"if (type.GetCustomAttributes(true).Any(a => a.GetType().FullName == PatchTools.harmonyPatchAllFullName)\n    && !type.GetCustomAttributes(true).Any(a => a is HarmonyAttribute && ((HarmonyAttribute)a).info.declaringType != null))\n    throw new Exception(\"HarmonyPatchAll needs a class-level HarmonyPatch(typeof(...))\");","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Always pair [HarmonyPatchAll] with a class-level declaring-type attribute","Prefer Harmony.CreateAndPatchAll(patchType, id) for explicitness"],"tags":["missing-attribute","harmony-patch-all","annotations","csharp"],"backgroundTag":"missing-required-argument","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"}