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

  1. Run with Harmony.DEBUG (Environment variable HARmony_DEBUG or Harmony.DEBUG) to get the full inner error/IL dump from CreateReplacement.
  2. Fix or disable transpilers on this method first; they are the most common cause of null replacements.
  3. Validate that all patch methods resolve their target and parameters (no nulls from AccessTools lookups).
  4. 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

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


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)