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

  1. Ensure transpilers never remove or relocate instructions that are branch targets without fixing labels/operands
  2. Deobfuscate the target assembly or choose a safer patch target (a caller/callee with clean IL)
  3. Bisect transpilers to find the one corrupting the instruction list, and use label-based operands instead of raw offsets
  4. 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

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


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)