pardeike/Harmony · error · NullReferenceException

Delegate has no defined original method

Error message

Delegate {typeof(DelegateType)} has no defined original method

What it means

AccessTools.HarmonyDelegate<DelegateType> derives the patch target from [HarmonyMethod]-annotated members merged from the delegate type. It throws NullReferenceException when that merged HarmonyMethod yields no original MethodInfo, meaning the delegate type does not define (or fails to resolve) any target method.

Solutions

  1. Add or fix the [HarmonyMethod]/[HarmonyPatch] annotation on the delegate type specifying the original method.
  2. Verify the annotated method name, declaring type, and argument types actually resolve via AccessTools.Method.
  3. Use MethodDelegate directly with an explicit MethodInfo if dynamic target resolution is not needed.

Example fix

// before
delegate int HealthGetter();
var d = AccessTools.HarmonyDelegate<HealthGetter>(entity);
// after
[HarmonyMethod(typeof(Player), nameof(Player.GetHealth))]
delegate int HealthGetter();
var d = AccessTools.HarmonyDelegate<HealthGetter>(entity);
Defensive patterns

Strategy: validation

Validate before calling

var hm = HarmonyMethodExtensions.GetMergedFromType(typeof(DelegateType));
if (hm.GetOriginalMethod() is not MethodInfo)
    throw new InvalidOperationException(typeof(DelegateType) + " has no [HarmonyMethod]/[HarmonyPatch]-defined original method");

Type guard

bool DelegateHasTarget<D>() where D : Delegate => HarmonyMethodExtensions.GetMergedFromType(typeof(D)).GetOriginalMethod() is MethodInfo;

Try / catch

try { var d = AccessTools.HarmonyDelegate<T>(instance); }
catch (NullReferenceException) { throw new InvalidOperationException("Add [HarmonyMethod] annotation defining the original method on " + typeof(T).Name); }

Prevention

When it happens

Trigger: Calling AccessTools.HarmonyDelegate<T>() where typeof(T) has no attributes from which GetMergedFromType can build a HarmonyMethod, or the attributes specify an original method that resolves to null (e.g. wrong method name/type in the annotation).

Common situations: Forgetting to annotate the delegate type or its methods with [HarmonyMethod]/[HarmonyPatch], misspelling the target method name in the annotation, or the annotated declaring type not being loaded.

Understand the failure class

Background: "missing required argument" and "the following required arguments were not provided": what required-argument errors mean and how to fix them — this error's family across 20 libraries.

Related errors


AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15). Data as JSON: /api/errors/70f596a5d9f1158a. Report an issue: GitHub.

Appendix: source

Thrown at Harmony/Tools/AccessTools.cs:2003

		/// Only applies for instance methods. If <c>null</c> (default), returned delegate is an open (a.k.a. unbound) instance delegate
		/// where an instance is supplied as the first argument to the delegate invocation; else, delegate is a closed (a.k.a. bound)
		/// instance delegate where the delegate invocation always applies to the given <paramref name="instance"/>.
		/// </param>
		/// <returns>A delegate of given <typeparamref name="DelegateType"/> to the method specified via [<see cref="HarmonyLib.HarmonyDelegate"/>]
		/// attributes on <typeparamref name="DelegateType"/></returns>
		/// <remarks>
		/// This calls <see cref="MethodDelegate{DelegateType}(MethodInfo, object, bool, Type[])"/> with the <c>method</c> and <c>virtualCall</c> arguments
		/// determined from the [<see cref="HarmonyLib.HarmonyDelegate"/>] attributes on <typeparamref name="DelegateType"/>,
		/// and the given <paramref name="instance"/> (for closed instance delegates).
		/// </remarks>
		///
		public static DelegateType HarmonyDelegate<DelegateType>(object instance = null) where DelegateType : Delegate
		{
			var harmonyMethod = HarmonyMethodExtensions.GetMergedFromType(typeof(DelegateType));
			harmonyMethod.methodType ??= MethodType.Normal;
			var method = harmonyMethod.GetOriginalMethod() as MethodInfo;
			if (method is null)
				throw new NullReferenceException($"Delegate {typeof(DelegateType)} has no defined original method");
			return MethodDelegate<DelegateType>(method, instance, harmonyMethod.nonVirtualDelegate is false, null);
		}

		/// <summary>Returns who called the current method</summary>
		/// <returns>The calling method/constructor (excluding the caller)</returns>
		///
		public static MethodBase GetOutsideCaller()
		{
			var trace = new StackTrace(true);
			foreach (var frame in trace.GetFrames())
			{
				var method = frame.GetMethod();
				if (method.DeclaringType?.Namespace != typeof(Harmony).Namespace)
					return method;
			}
			throw new Exception("Unexpected end of stack trace");
		}

View on GitHub (pinned to e7872dc170)