pardeike/Harmony · info · Exception
E0
Error message
E0
What it means
This Exception with message 'E0' is thrown intentionally by the static Class.Test() helper in Harmony's FinalizerPatches.cs:64 test fixture, after printing 'Test'. It is the controlled exception payload used to verify that Harmony finalizer patches (methods with an Exception __exception parameter) observe and can consume or rethrow exceptions raised inside patched methods. It is not a library defect; it is the expected exception a finalizer test must catch.
Solutions
- Add a finalizer patch method (static void/bool Finalizer(Exception __exception)) to the patch class so 'E0' is observed and handled instead of escaping.
- In the finalizer, return true / return void normally to swallow the exception, or set __exception = null depending on the desired semantics, matching what the test asserts.
- If you need the exception to propagate for the test, ensure the test harness expects it (e.g. Assert.Throws) rather than letting the runner report it as failure.
- Verify the patch is applied to the correct target (static Class.Test) — a mistyped HarmonyPatch target leaves the method unpatched.
- Pass 'E0' through unchanged if downstream assertions compare ex.Message; do not wrap it in another exception type.
Example fix
// before: target throws, no finalizer
static class Class
{
public static void Test()
{
TestTools.WriteLine("Test", false);
throw new Exception("E0");
}
}
// after: finalizer patch consumes the exception
[HarmonyPatch(typeof(Class), nameof(Class.Test))]
static class Class_Patch
{
static void Finalizer(Exception __exception)
{
TestTools.WriteLine($"caught {__exception?.Message}", false);
// returning normally swallows 'E0'
}
} Defensive patterns
Strategy: try-catch
Validate before calling
var m = typeof(Class).GetMethod(nameof(Class.Test), BindingFlags.Public | BindingFlags.Static);
if (!m.IsStatic) throw new InvalidOperationException("Expected static Class.Test for finalizer patching"); Type guard
static bool IsE0(Exception ex) => ex?.Message == "E0";
Try / catch
[HarmonyPatch(typeof(Class), nameof(Class.Test))]
static class ClassPatch
{
static bool Finalizer(Exception __exception)
{
if (__exception != null && __exception.Message == "E0")
return true; // swallow the controlled test exception
return false; // rethrow anything unexpected
}
} Prevention
- Declare a finalizer with an Exception __exception parameter whenever patching methods that can throw.
- Use the finalizer's bool return (true = swallow) to control propagation deterministically.
- Assert on exception message ('E0') inside the finalizer so unrelated exceptions still propagate.
- Confirm patch application with Harmony.GetPatchInfo before invoking the target.
- Keep TestLogger/NonParallelizable fixtures isolated so 'E0' is never attributed to another test.
When it happens
Trigger: Invoking the static Class.Test() (via reflection or a patched delegate) during FinalizerPatches2 test runs, e.g. Harmony.PatchAll on the FinalizerPatches assembly followed by TestTools.Run<Class.Test>() style invocation, or any test asserting the finalizer received an exception whose Message == 'E0'. It triggers whenever the patched target executes its unconditional throw.
Common situations: Patch authors replicating Harmony's finalizer tests hit this when their finalizer does not declare the __exception parameter or returns the wrong result sentinel, letting 'E0' escape to the test runner. It also appears when users patch a method that always throws and forget a finalizer, and when porting test code across Harmony versions where finalizer result semantics (bool result vs void) changed.
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
- fail
- Unbalanced exception markers – cannot rewrite.
- The type must declare an empty constructor (the constructor…
- position( ) + count( ) > buffer.Length( )
- Multiple loaded HarmonySharedState types prevent safe…
AI-assisted analysis of pardeike/Harmony@e7872dc170 (2026-09-15).
Data as JSON: /api/errors/3baf81791fbcb064.
Report an issue: GitHub.
Appendix: source
Thrown at HarmonyTests/Patching/FinalizerPatches.cs:64
[HarmonyPatch(typeof(Class), nameof(Class.Test))]
[HarmonyPatchCategory("finalizer-test")]
[HarmonyPriority(Priority.High)]
static class Patch2
{
static Exception Finalizer(Exception __exception)
{
_ = progress.Append($"Finalizer 2 {__exception?.Message ?? "-"} -> E-2\n");
return new Exception("E-2");
}
}
}
static class Class
{
public static void Test()
{
TestTools.WriteLine("Test", false);
throw new Exception("E0");
}
}
[TestFixture, NonParallelizable]
public class FinalizerPatches2 : TestLogger
{
static Dictionary<string, object> info;
[Test]
public void Test_NoThrowingVoidMethod_EmptyFinalizer()
{
Patch();
AssertNoThrownException();
AssertGotNoResult();
}
[Test]
public void Test_NoThrowingVoidMethod_EmptyFinalizerWithExceptionArg()
View on GitHub (pinned to e7872dc170)