pardeike/Harmony · error · ArgumentOutOfRangeException
Instruction offset is less than 0
Error message
Instruction offset {offset} is less than 0 What it means
While re-emitting/copied IL, MethodBodyReader.GetInstruction validates that a requested instruction offset is non-negative. A negative offset means the operand resolution computed a branch/jump target below the start of the method body, which indicates a malformed or mis-decoded IL stream rather than a problem in the user's patch code. Harmony throws ArgumentOutOfRangeException with the offset value for diagnosis.
Solutions
- Check whether the target method is obfuscated and deobfuscate or patch a different method
- Narrow which transpiler triggers the failure by removing transpilers one at a time
- Report the failing method (FullDescription) to Harmony maintainers if ordinary IL triggers it — likely a reader bug
- Avoid writing transpilers that construct CodeInstruction offsets/labels manually; rely on Harmony's label APIs
Example fix
// before
foreach (var ci in instructions) // blindly rewriting, can corrupt offsets
if (ci.opcode == OpCodes.Br) ci.operand = someAbsoluteIntOffset;
// after
foreach (var ci in instructions)
if (ci.opcode == OpCodes.Br)
{
var lbl = generator.DefineLabel();
ci.labels.Add(lbl);
ci.opcode = OpCodes.Br;
ci.operand = lbl; // use labels, not raw offsets
} Defensive patterns
Strategy: try-catch
Validate before calling
// no pre-call validation is practical; validate at patch-install time
try { harmony.Patch(target, transpiler: myTranspiler); Log.Info("transpiler ok"); }
catch (ArgumentOutOfRangeException ex) { Log.Error($"{target} IL decode failed: {ex.Message}"); } Try / catch
try { harmony.Patch(target, transpiler: trans); }
catch (ArgumentOutOfRangeException ex) when (ex.ParamName == "offset")
{ Log.Error($"IL offset issue while transpiling {target.FullDescription()}: {ex.Message}"); throw; } Prevention
- Do not write raw integer offsets into CodeInstruction operands; use labels
- Never delete instructions that carry labels without retargeting them first
- Test transpilers against unobfuscated builds before shipping
- Keep Harmony updated; IL decoding fixes land regularly
When it happens
Trigger: Transpiling a method whose IL contains switch/branch targets that decode to negative offsets; processing an IL stream read from a method body that the reader mis-parses (obfuscated or exotic IL); bugs in custom transpilers that manufacture instructions with negative offsets.
Common situations: Transpiling obfuscated game assemblies where IL is manipulated to confuse decompilers; methods with unusual switch tables on older Mono runtimes; transpilers replacing/inserting instructions with computed labels incorrectly.
Related errors
- Instruction offset is outside valid range 0
- The type must declare an empty constructor (the constructor…
- Can not get IL bytes of method
- Cannot find instruction for
- Unexpected null argument
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/64c0f1c2e4253418.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Internal/MethodCopier.cs:609
}
}
else
{
instruction.operand = GetParameter(idx);
instruction.argument = idx;
}
break;
}
default:
throw new NotSupportedException();
}
}
ILInstruction GetInstruction(int offset, bool isEndOfInstruction)
{
if (offset < 0)
throw new ArgumentOutOfRangeException(nameof(offset), offset, $"Instruction offset {offset} is less than 0");
var lastInstructionIndex = ilInstructions.Count - 1;
var instruction = ilInstructions[lastInstructionIndex];
if (offset > instruction.offset + instruction.GetSize() - 1)
throw new ArgumentOutOfRangeException(nameof(offset), offset, $"Instruction offset {offset} is outside valid range 0 - {instruction.offset + instruction.GetSize() - 1}");
var min = 0;
var max = lastInstructionIndex;
while (min <= max)
{
var mid = min + ((max - min) / 2);
instruction = ilInstructions[mid];
if (isEndOfInstruction)
{
if (offset == instruction.offset + instruction.GetSize() - 1)
return instruction;
}
View on GitHub (pinned to e7872dc170)