pardeike/Harmony · error · Exception
Cannot directly reference dynamic method \
Error message
Cannot directly reference dynamic method \"{patch.FullDescription()}\" in Harmony. Use a factory method instead that will return the dynamic method. What it means
A DynamicMethod cannot be referenced directly as a patch in Harmony because its IL body may be freed/recollected before the patch is applied. Harmony requires a factory method (a Func<DynamicMethod>) so the dynamic method can be re-emitted on demand, e.g. when patches are rebuilt or unpatched/repatched.
Solutions
- Pass a factory method instead: a MethodInfo returning DynamicMethod (with optional object[] parameter) so Harmony can re-create the method on demand
- If the method is truly static and long-lived, compile it to a normal method or use a static wrapper method as the patch
- Use PatchTools.GetPatchMethod / factory-style helper to register the dynamic method
Example fix
// before DynamicMethod dm = EmitReplacement(); new Patch(dm, 0, null, -1, null, null, false); // after static DynamicMethod Factory() => EmitReplacement(); new Patch(typeof(Patches).GetMethod(nameof(Factory), BindingFlags.NonPublic | BindingFlags.Static), 0, null, -1, null, null, false);
Defensive patterns
Strategy: type-guard
Validate before calling
if (candidate is DynamicMethod) candidate = WrapInFactory(candidate);
Type guard
static bool IsDirectDynamicMethod(MethodInfo m) => m is System.Reflection.Emit.DynamicMethod;
Try / catch
try { new Patch(m, ...); } catch (Exception e) when (e.Message.Contains("dynamic method")) { /* use factory */ } Prevention
- Always register dynamic patch methods through factory MethodInfos
- Never store bare DynamicMethod instances in patch lists
When it happens
Trigger: Passing a System.Reflection.Emit.DynamicMethod to the Patch(MethodInfo, int, string, int, string[], string[], bool) constructor, directly or via PatchMethods/ManualPatchMethods lists.
Common situations: Building patches at runtime with Reflection.Emit; migrating code that previously used MethodInfo everywhere; storing dynamic methods created by other libraries (e.g. old serialization frameworks) and feeding them to Harmony.
Understand the failure class
Background: UnsupportedOperationException and "is not supported" errors: when a library deliberately refuses a call — this error's family across 30 libraries.
Related errors
- cannot contain zeros
- [ ]
- Patching exception in method
- Method has wrong return type (should be assignable to )
- Null method for
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/523f7f3d7aab65c3.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Public/Patch.cs:83
{
patchMethod = value;
methodToken = patchMethod.MetadataToken;
moduleGUID = patchMethod.Module.ModuleVersionId.ToString();
}
}
/// <summary>Creates a patch</summary>
/// <param name="patch">The method of the patch</param>
/// <param name="index">Zero-based index</param>
/// <param name="owner">An owner (Harmony ID)</param>
/// <param name="priority">The priority, see <see cref="Priority"/></param>
/// <param name="before">A list of Harmony IDs for patches that should run after this patch</param>
/// <param name="after">A list of Harmony IDs for patches that should run before this patch</param>
/// <param name="debug">A flag that will log the replacement method via <see cref="FileLog"/> every time this patch is used to build the replacement, even in the future</param>
///
public Patch(MethodInfo patch, int index, string owner, int priority, string[] before, string[] after, bool debug)
{
if (patch is DynamicMethod) throw new Exception($"Cannot directly reference dynamic method \"{patch.FullDescription()}\" in Harmony. Use a factory method instead that will return the dynamic method.");
this.index = index;
this.owner = owner;
this.priority = priority == -1 ? Priority.Normal : priority;
this.before = before ?? [];
this.after = after ?? [];
this.debug = debug;
PatchMethod = patch;
}
/// <summary>Creates a patch</summary>
/// <param name="method">The method of the patch</param>
/// <param name="index">Zero-based index</param>
/// <param name="owner">An owner (Harmony ID)</param>
public Patch(HarmonyMethod method, int index, string owner)
: this(method.method, index, owner, method.priority, method.before, method.after, method.debug ?? false) { }
internal int MethodToken => methodToken;
View on GitHub (pinned to e7872dc170)