pardeike/Harmony · error · ArgumentNullException

Value cannot be null. (Parameter 'generator')

Error message

Value cannot be null. (Parameter 'generator')

What it means

MethodCopier.GetInstructions copies a method's instructions into a caller-supplied ILGenerator so transpilers can run on them. The generator is essential (original locals are declared on it), so a null generator is rejected with ArgumentNullException('generator').

Solutions

  1. Create a valid ILGenerator (e.g. from a DynamicMethod or MethodBuilder) and pass it to GetInstructions
  2. Trace where your generator value comes from and ensure it is initialized before the call
  3. If using Harmony's high-level Patch API instead, the generator is created for you — prefer harmony.Patch over raw internals
  4. Add a guard that fails early with your own message when the generator could not be created

Example fix

// before
var instructions = MethodCopier.GetInstructions(null, originalMethod, 3);
// after
var dm = new DynamicMethod("Copy", originalMethod.ReturnType, originalMethod.GetParameters().Select(p => p.ParameterType).ToArray());
var instructions = MethodCopier.GetInstructions(dm.GetILGenerator(), originalMethod, 3);
Defensive patterns

Strategy: validation

Validate before calling

if (generator is null) throw new InvalidOperationException("ILGenerator must be created before calling MethodCopier.GetInstructions");

Try / catch

try { var instrs = MethodCopier.GetInstructions(generator, method, maxTranspilers); }
catch (ArgumentNullException ex) when (ex.ParamName == "generator") { /* create DynamicMethod/ILGenerator and retry */ }

Prevention

When it happens

Trigger: Calling MethodCopier.GetInstructions(null, method, maxTranspilers) or a patch pipeline that resolved its ILGenerator lazily and got null (e.g. MethodPatcher building a replacement body without a valid generator).

Common situations: Custom patch tooling built on Harmony internals passing a generator created conditionally; refactors where the generator creation step was skipped; using GetInstructions outside Harmony's normal patch flow without creating a DynamicMethod/ILGenerator first.

Related errors


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

Appendix: source

Thrown at Harmony/Internal/MethodCopier.cs:44

		internal MethodCopier(MethodCreatorConfig config)
		{
			if (config.MethodBase is null)
				throw new ArgumentNullException("config.methodbase");
			reader = new MethodBodyReader(config.MethodBase, config.il);
			reader.DeclareVariables(config.originalVariables);
			reader.GenerateInstructions();
			reader.SetDebugging(config.debug);
		}

		internal void AddTranspiler(MethodInfo transpiler) => transpilers.Add(transpiler);

		internal List<CodeInstruction> Finalize(bool stripLastReturn, out bool hasReturnCode, out bool methodEndsInDeadCode, List<Label> endLabels)
			=> reader.FinalizeILCodes(transpilers, stripLastReturn, out hasReturnCode, out methodEndsInDeadCode, endLabels);

		internal static List<CodeInstruction> GetInstructions(ILGenerator generator, MethodBase method, int maxTranspilers)
		{
			if (generator is null)
				throw new ArgumentNullException(nameof(generator));
			if (method is null)
				throw new ArgumentNullException(nameof(method));

			var originalVariables = MethodPatcherTools.DeclareOriginalLocalVariables(generator, method);
			var copier = new MethodCopier(method, generator, originalVariables);

			var info = Harmony.GetPatchInfo(method);
			if (info is not null)
			{
				var sortedTranspilers = PatchFunctions.GetSortedPatchMethods(method, [.. info.Transpilers], false);
				for (var i = 0; i < maxTranspilers && i < sortedTranspilers.Count; i++)
					copier.AddTranspiler(sortedTranspilers[i]);
			}

			return copier.Finalize(false, out _, out _, null);
		}
	}

View on GitHub (pinned to e7872dc170)