pardeike/Harmony · error · InvalidOperationException
Unbalanced exception markers – cannot rewrite.
Error message
Unbalanced exception markers – cannot rewrite.
What it means
FaultBlockRewriter converts C# 'fault' style exception blocks (identified by special fault markers) into rewritten IL. During Rewrite it pairs each fault marker with a matching begin/end exception marker; if either matching marker cannot be found the instruction stream is unbalanced and rewriting cannot proceed safely, so it throws InvalidOperationException rather than producing corrupt IL.
Solutions
- Review your transpilers for instructions that remove, reorder, or clone fault/exception block boundaries (Branch, Leave, marker instructions)
- Exclude the method from fault rewriting or patch a wrapper method instead
- Upgrade Harmony in case the marker-matching logic handles your IL pattern in a newer release
- Inspect the method's exception regions with the CLI or MethodBody.ExceptionHandlingClauses to understand the block layout
Example fix
// before (transpiler deletes fault-block boundary) codes.RemoveAll(c => c.opcode == OpCodes.Leave); // after (only remove leaves outside exception regions) codes.RemoveAll(c => c.opcode == OpCodes.Leave && !IsInsideExceptionRegion(codes, c));
Defensive patterns
Strategy: try-catch
Try / catch
try { /* transpile via harmony.Patch with your transpiler */ }
catch (InvalidOperationException ex) when (ex.Message.Contains("Unbalanced exception markers")) { /* fall back: patch without that transpiler or skip method */ } Prevention
- Never delete/reorder exception-region boundary instructions (Leave, marker code) in transpilers
- Test transpilers against methods that contain fault/finally blocks
- Clone whole instructions and keep block structure intact when editing CodeInstruction lists
- Prefer inserting over removing IL in exception-heavy methods
When it happens
Trigger: Rewrite() processing an instruction list whose fault markers do not line up with FindMatchingBeginException/FindMatchingEndException results — e.g. transpilers inserted or removed exception-block boundary instructions, or nested/reordered try-fault blocks breaking marker pairing.
Common situations: A custom transpiler that deletes or duplicates instructions inside a method containing fault blocks; combining Harmony patches on methods compiled with unusual exception-region layouts; older/newer compiler output that confuses the marker matcher.
Understand the failure class
Background: "This is a bug, please report it": internal invariant violations, unreachable panics, and SNH errors explained — this error's family across 47 libraries.
Related errors
- Value cannot be null. (Parameter 'generator')
- Wrong null argument
- Wrong Emit argument type
- Unexpected null argument
- fail
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/5dce957370f9622b.
Report an issue: GitHub.
Appendix: source
Thrown at Harmony/Internal/FaultBlockRewriter.cs:68
var i = 0;
var rewritten = new List<CodeInstruction>(instructions.Count * 2);
while (i < instructions.Count)
{
var cur = instructions[i];
if (cur.HasBlock(ExceptionBlockType.BeginFaultBlock) == false)
{
rewritten.Add(new CodeInstruction(cur));
++i;
continue;
}
var beginExceptionIdx = FindMatchingBeginException(rewritten);
var endExceptionIdx = FindMatchingEndException(instructions, i + 1);
if (beginExceptionIdx < 0 || endExceptionIdx < 0)
throw new InvalidOperationException("Unbalanced exception markers – cannot rewrite.");
var faultBody = new List<CodeInstruction>();
for (var k = i; k < endExceptionIdx; ++k)
faultBody.Add(CloneWithoutFaultMarker(instructions[k]));
i = endExceptionIdx + 1;
var failedLocal = generator.DeclareLocal(typeof(bool));
var skipFault = generator.DefineLabel();
rewritten.AddRange([
Nop.WithBlocks(new ExceptionBlock(ExceptionBlockType.BeginCatchBlock, typeof(object))),
Pop,
Ldc_I4_1,
Stloc[failedLocal.LocalIndex],
Rethrow,
Nop.WithBlocks(new ExceptionBlock(ExceptionBlockType.BeginFinallyBlock)),
Ldloc[failedLocal.LocalIndex],
View on GitHub (pinned to e7872dc170)