pardeike/Harmony · critical · MissingMethodException
Cannot create replacement for
Error message
Cannot create replacement for {original.FullDescription()} What it means
UpdateWrapper builds the detour replacement method from sorted patches/transpilers and calls CreateReplacement on the patcher. If the patcher returns null replacement, Harmony cannot compile a new method body for the original and throws this MissingMethodException, since the wrapper creation pipeline produced nothing to detour with.
Solutions
- Run with Harmony.DEBUG (Environment variable HARmony_DEBUG or Harmony.DEBUG) to get the full inner error/IL dump from CreateReplacement.
- Fix or disable transpilers on this method first; they are the most common cause of null replacements.
- Validate that all patch methods resolve their target and parameters (no nulls from AccessTools lookups).
- Catch MissingMethodException around Patch() to report which original failed and skip it.
Example fix
// before
harmony.PatchAll(); // crashes on bad transpiler
// after
try { harmony.Patch(original, prefix: prefix); }
catch (MissingMethodException ex) { Logger.Error($"Patch failed: {ex.Message}"); } Defensive patterns
Strategy: try-catch
Validate before calling
if (AccessTools.Method(targetType, targetName) is null)
throw new InvalidOperationException("Target method missing before patching");
foreach (var t in transpilers) DebugDumpInstructions(t, original); // dry-run in dev Try / catch
try { harmony.Patch(original, transpiler: transpiler); }
catch (MissingMethodException ex) when (ex.Message.Contains("Cannot create replacement"))
{ Logger.Error($"Wrapper generation failed for {original.Name}: {ex.Message}"); } Prevention
- Test every patch in CI with Harmony.DEBUG enabled to surface replacement failures early.
- Keep transpilers minimal and defensive (try/catch inside the transpiler body).
- Pin Harmony and target-library versions together; re-verify patches on upgrades.
- Isolate patches per method so one failure doesn't abort PatchAll.
When it happens
Trigger: PatchClassProcessor.Patch()/Harmony.Patch runs UpdateWrapper and the internal MethodPatcher fails to produce a replacement body — typically from a failing transpiler, unresolvable patch parameter injection, or invalid patch method signatures that abort replacement generation.
Common situations: Transpilers throwing or yielding invalid IL, patches referencing missing types (type-load issues in trimmed/AOT environments), or combined prefix/postfix/finalizer sets that the generator cannot reconcile.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Could not create replacement method
- __state type mismatch in patch
- Prefix patch has not "bool" or "void" return type
- Return type of pass through postfix
- Postfix patch must have a "void" return type
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/602ae24eb42a2ef6.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Internal/PatchFunctions.cs:37
var sortedPostfixes = GetSortedPatchMethods(original, patchInfo.postfixes, debug);
var sortedTranspilers = GetSortedPatchMethods(original, patchInfo.transpilers, debug);
var sortedFinalizers = GetSortedPatchMethods(original, patchInfo.finalizers, debug);
var sortedInnerPrefixes = GetInfixes(patchInfo.innerprefixes);
var sortedInnerPostfixes = GetInfixes(patchInfo.innerpostfixes);
var patcher = new MethodCreator(new MethodCreatorConfig(
original,
null,
sortedPrefixes,
sortedPostfixes,
sortedTranspilers,
sortedFinalizers,
sortedInnerPrefixes,
sortedInnerPostfixes,
debug
));
var (replacement, finalInstructions) = patcher.CreateReplacement();
if (replacement is null) throw new MissingMethodException($"Cannot create replacement for {original.FullDescription()}");
try
{
PatchTools.DetourMethod(original, replacement);
}
catch (Exception ex)
{
throw HarmonyException.Create(ex, finalInstructions);
}
return replacement;
}
internal static MethodInfo ReversePatch(HarmonyMethod standin, MethodBase original, MethodInfo postTranspiler)
{
if (standin is null)
throw new ArgumentNullException(nameof(standin));
if (standin.method is null)
throw new ArgumentNullException(nameof(standin), $"{nameof(standin)}.{nameof(standin.method)} is NULL");
View on GitHub (pinned to e7872dc170)