pardeike/Harmony · error · ArgumentOutOfRangeException
Instruction offset is outside valid range 0
Error message
Instruction offset {offset} is outside valid range 0 - {instruction.offset + instruction.GetSize() - 1} What it means
GetInstruction also bounds-checks the requested offset against the last instruction's end (instruction.offset + GetSize() - 1). An offset beyond the emitted IL range means operand resolution pointed past the method body — again a symptom of IL decoding trouble or a transpiler producing inconsistent instruction streams. Harmony throws ArgumentOutOfRangeException showing the valid range.
Solutions
- Ensure transpilers never remove or relocate instructions that are branch targets without fixing labels/operands
- Deobfuscate the target assembly or choose a safer patch target (a caller/callee with clean IL)
- Bisect transpilers to find the one corrupting the instruction list, and use label-based operands instead of raw offsets
- If plain vanilla IL triggers it, file a Harmony bug with the failing method's description
Example fix
// before
list.RemoveAll(ci => ci.opcode == OpCodes.Nop); // removes branch targets
// after
// keep instructions carrying labels, or retarget their labels first
foreach (var ci in instructions.Where(ci => ci.opcode == OpCodes.Nop && ci.labels.Count == 0 && ci.opcode != OpCodes.Nop || (ci.opcode == OpCodes.Nop && ci.labels.Count == 0)))
list.Remove(ci); // only strip label-free nops Defensive patterns
Strategy: try-catch
Validate before calling
// validate your transpiler in isolation on the target method at startup: var copy = PatchProcessor.ReadMethodBody(target); // or run the patch in a try/catch during boot
Try / catch
try { harmony.Patch(target, transpiler: trans); }
catch (ArgumentOutOfRangeException ex) when (ex.Message.Contains("outside valid range"))
{ Log.Error($"Branch target beyond IL end while transpiling {target}: {ex.Message}"); } Prevention
- Bisect transpilers when a target fails to find the offending one
- Preserve instruction labels when removing/replacing instructions
- Avoid transpiling obfuscated methods; patch an alternative target instead
- Pin to a recent Harmony version
When it happens
Trigger: Branch/switch operands in the copied method resolving beyond the end of the IL byte array; transpilers that replaced instructions while leaving stale operand references; decoding IL from obfuscated or hand-tweaked assemblies.
Common situations: Transpiling modded/obfuscated assemblies; methods where a custom transpiler removed instructions that other instructions still branch to; Mono runtime IL quirks with switch opcodes.
Related errors
- Instruction offset is less than 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/802bbbeb7bfb8bcb.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Internal/MethodCopier.cs:614
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;
}
else
{
if (offset == instruction.offset)
return instruction;
}
View on GitHub (pinned to e7872dc170)