pardeike/Harmony · error · Exception

Wrong null argument

Error message

Wrong null argument: {codeInstruction}

What it means

During EmitCodes, an instruction with an InlineSig operand type (a calli signature) arrived with a null operand. Harmony's emitter cannot pass a null call-site signature to the underlying emitter, so this indicates malformed/corrupted IL in the transpiled instruction list.

Solutions

  1. Find the transpiler producing the calli instruction and set its operand to a valid signature (ILGenerator-compatible SignatureHelper/ICallSiteGenerator).
  2. Remove or replace the null-operand calli instruction in the transpiled list.
  3. Dump the transpiled instructions (Harmony.DEBUG logging) to locate the offending instruction.

Example fix

// before
yield return new CodeInstruction(OpCodes.Calli, null);

// after
yield return new CodeInstruction(OpCodes.Calli, signatureHelper); // valid ICallSiteGenerator operand
Defensive patterns

Strategy: type-guard

Validate before calling

foreach (var ci in transpiledInstructions)
    if (ci.opcode.OperandType == OperandType.InlineSig && ci.operand is null)
        throw new InvalidOperationException("calli instruction without signature");

Type guard

static bool HasValidSigOperand(CodeInstruction ci) =>
    ci.opcode.OperandType != OperandType.InlineSig || ci.operand is ICallSiteGenerator;

Try / catch

try { harmony.Patch(original, transpiler: t); }
catch (Exception ex) when (ex.Message.StartsWith("Wrong null argument"))
{ Logger.Error($"Transpiler emitted calli with null operand: {ex.Message}"); }

Prevention

When it happens

Trigger: A transpiler emits an Instruction whose opcode is calli (InlineSig) but sets operand to null, or an IL manipulation step stripped the signature operand before EmitCodes runs.

Common situations: Custom transpilers that copy instructions but forget the operand, IL manipulation libraries (e.g. manual Cecil-style edits) producing calli without a signature, or hand-built CodeInstruction lists.

Related errors


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

Appendix: source

Thrown at Harmony/Internal/MethodCreatorTools.cs:634

				// mark all labels
				codeInstruction.labels.Do(label => emitter.MarkLabel(label));

				// start all exception blocks
				codeInstruction.blocks.Do(block => emitter.MarkBlockBefore(block, out var _));

				var code = codeInstruction.opcode;
				var operand = codeInstruction.operand;

				switch (code.OperandType)
				{
					case OperandType.InlineNone:
						if (codeInstruction.IsAnnotation() == null)
							emitter.Emit(code);
						break;

					case OperandType.InlineSig:
						if (operand is null)
							throw new Exception($"Wrong null argument: {codeInstruction}");
						if ((operand is ICallSiteGenerator) is false)
							throw new Exception($"Wrong Emit argument type {operand.GetType()} in {codeInstruction}");
						emitter.Emit(code, (ICallSiteGenerator)operand);
						break;

					default:
						if (operand is null)
							throw new Exception($"Wrong null argument: {codeInstruction}");
						emitter.DynEmit(code, operand);
						break;
				}

				codeInstruction.blocks.Do(block => emitter.MarkBlockAfter(block));
			});
		}

		static List<CodeInstruction> InitializeOutParameter(int argIndex, Type type)
		{

View on GitHub (pinned to e7872dc170)