{"record":{"id":"64c0f1c2e4253418","repo":"pardeike/Harmony","slug":"instruction-offset-offset-is-less-than-0","errorCode":null,"errorMessage":"Instruction offset {offset} is less than 0","messagePattern":"Instruction offset (.+?) is less than 0","errorType":"exception","errorClass":"ArgumentOutOfRangeException","httpStatus":null,"severity":"error","filePath":"Harmony/Internal/MethodCopier.cs","lineNumber":609,"sourceCode":"\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse\r\n\t\t\t\t\t{\r\n\t\t\t\t\t\tinstruction.operand = GetParameter(idx);\r\n\t\t\t\t\t\tinstruction.argument = idx;\r\n\t\t\t\t\t}\r\n\t\t\t\t\tbreak;\r\n\t\t\t\t}\r\n\r\n\t\t\t\tdefault:\r\n\t\t\t\t\tthrow new NotSupportedException();\r\n\t\t\t}\r\n\t\t}\r\n\r\n\t\tILInstruction GetInstruction(int offset, bool isEndOfInstruction)\r\n\t\t{\r\n\t\t\tif (offset < 0)\r\n\t\t\t\tthrow new ArgumentOutOfRangeException(nameof(offset), offset, $\"Instruction offset {offset} is less than 0\");\r\n\r\n\t\t\tvar lastInstructionIndex = ilInstructions.Count - 1;\r\n\t\t\tvar instruction = ilInstructions[lastInstructionIndex];\r\n\t\t\tif (offset > instruction.offset + instruction.GetSize() - 1)\r\n\t\t\t\tthrow new ArgumentOutOfRangeException(nameof(offset), offset, $\"Instruction offset {offset} is outside valid range 0 - {instruction.offset + instruction.GetSize() - 1}\");\r\n\r\n\t\t\tvar min = 0;\r\n\t\t\tvar max = lastInstructionIndex;\r\n\t\t\twhile (min <= max)\r\n\t\t\t{\r\n\t\t\t\tvar mid = min + ((max - min) / 2);\r\n\t\t\t\tinstruction = ilInstructions[mid];\r\n\r\n\t\t\t\tif (isEndOfInstruction)\r\n\t\t\t\t{\r\n\t\t\t\t\tif (offset == instruction.offset + instruction.GetSize() - 1)\r\n\t\t\t\t\t\treturn instruction;\r\n\t\t\t\t}\r","sourceCodeStart":591,"sourceCodeEnd":627,"githubUrl":"https://github.com/pardeike/Harmony/blob/e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c/Harmony/Internal/MethodCopier.cs#L591-L627","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\nforeach (var ci in instructions) // blindly rewriting, can corrupt offsets\n    if (ci.opcode == OpCodes.Br) ci.operand = someAbsoluteIntOffset;\n// after\nforeach (var ci in instructions)\n    if (ci.opcode == OpCodes.Br)\n    {\n        var lbl = generator.DefineLabel();\n        ci.labels.Add(lbl);\n        ci.opcode = OpCodes.Br;\n        ci.operand = lbl; // use labels, not raw offsets\n    }","handlingStrategy":"try-catch","validationCode":"// no pre-call validation is practical; validate at patch-install time\ntry { harmony.Patch(target, transpiler: myTranspiler); Log.Info(\"transpiler ok\"); }\ncatch (ArgumentOutOfRangeException ex) { Log.Error($\"{target} IL decode failed: {ex.Message}\"); }","typeGuard":null,"tryCatchPattern":"try { harmony.Patch(target, transpiler: trans); }\ncatch (ArgumentOutOfRangeException ex) when (ex.ParamName == \"offset\")\n{ Log.Error($\"IL offset issue while transpiling {target.FullDescription()}: {ex.Message}\"); throw; }","preventionTips":["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"],"tags":["harmony","il","argument-out-of-range"],"backgroundTag":"argument-out-of-range","analyzedSha":"e7872dc17008bc0ca2b3de1f53fd4120dbd7a17c","analyzedAt":"2026-09-15T22:47:11.550Z","contentChangedAt":"2026-09-15T22:47:11.550Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}