pardeike/Harmony · error · Exception
Wrong Emit argument type
Error message
Wrong Emit argument type {operand.GetType()} in {codeInstruction} What it means
For InlineSig (calli) instructions Harmony requires the operand to implement ICallSiteGenerator. If the operand is non-null but of another type (e.g. a SignatureHelper from a different emitter abstraction or a random object), EmitCodes throws this instead of silently emitting broken IL.
Solutions
- Ensure the calli operand is created via the same IL generator's SignatureHelper/ICallSiteGenerator mechanism.
- Rebuild the signature for the calli site instead of copying the operand from a read body.
- Check that all Harmony patching assemblies reference the same Harmony version.
Example fix
// before instr.operand = someMethodInfo; // wrong type for calli // after instr.operand = il.CreateSignature(...); // proper ICallSiteGenerator signature
Defensive patterns
Strategy: type-guard
Validate before calling
foreach (var ci in transpiledInstructions)
if (ci.opcode.OperandType == OperandType.InlineSig && ci.operand is not null && ci.operand is not ICallSiteGenerator)
throw new InvalidOperationException($"Bad calli operand type {ci.operand.GetType()}"); Type guard
static bool IsCallSiteOperand(object operand) => operand is ICallSiteGenerator;
Try / catch
try { harmony.Patch(original, transpiler: t); }
catch (Exception ex) when (ex.Message.Contains("Wrong Emit argument type"))
{ Logger.Error($"Bad calli operand: {ex.Message}"); } Prevention
- Ensure transpiler code targets the same Harmony version across all assemblies.
- Do not copy operands from body readers into calli instructions; regenerate signatures.
- Add unit tests running every transpiler through a real Patch/PatchAll call.
When it happens
Trigger: A transpiler assigns a wrong-typed operand to a calli instruction — for example a SignatureHelper created for a different IL generator, a byte array, or a MethodInfo — and the wrapper is emitted.
Common situations: Reusing transpiler code across IL emitter versions, copying calli operands from a MethodInfo body reader into CodeInstruction without converting, or mixing Harmony versions where the signature type differs.
Understand the failure class
Background: Type mismatch errors: IllegalArgumentException, TypeError and type guards across 150 open-source libraries — this error's family across 150 libraries.
Related errors
- Wrong null argument
- Unbalanced exception markers – cannot rewrite.
- Value cannot be null. (Parameter 'generator')
- __state type mismatch in patch
- Return type of pass through postfix
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/e5eb24461f4622e1.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Internal/MethodCreatorTools.cs:636
// 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)
{
var codes = new List<CodeInstruction>();
if (type.IsByRef)
View on GitHub (pinned to e7872dc170)