pardeike/Harmony · info · ArgumentException
fail
Error message
fail
What it means
This ArgumentException with message 'fail' is deliberately thrown by the last IL instruction of LateThrowClass1.Method in Harmony's own test assets (Specials.cs:176). It exists to verify that Harmony's patching (especially finalizers / exception handlers appended by patches) correctly intercepts an exception thrown as the very last instruction before 'ret'. Seeing this error means the patched method executed and threw as designed; it only indicates a test failure when it escapes and is not caught by the expected finalizer patch.
Solutions
- Ensure the intended Harmony finalizer patch (e.g. LateThrowClass_Patch1) is actually applied before calling LateThrowClass1.Method — verify with PatchProcessor.Patch() return value or Harmony.GetPatchInfo.
- If your own finalizer sees this exception, return normally (or handle ex) instead of rethrowing, so the 'last-IL throw' is consumed as the test expects.
- Pass a string of Length == 2 to avoid entering the throw path during unrelated debugging.
- When reproducing in user code, wrap the patched call in try/catch to confirm Harmony's finalizer ordering behavior.
- Update or re-run with the matching Harmony version if patch application silently no-ops due to target resolution changes.
Example fix
// before: raw call, exception escapes
LateThrowClass1 lc = new LateThrowClass1();
lc.Method("abc"); // throws ArgumentException("fail")
// after: let the applied finalizer patch handle it, or guard explicitly
try
{
lc.Method("abc");
}
catch (ArgumentException ex) when (ex.Message == "fail")
{
// finalizer patch expected to handle this; log if it escaped
} Defensive patterns
Strategy: try-catch
Validate before calling
var patches = Harmony.GetPatchInfo(typeof(LateThrowClass1).GetMethod(nameof(LateThrowClass1.Method)));
if (patches == null || patches.Finalizers.Count == 0)
throw new InvalidOperationException("LateThrowClass1.Method is not patched with a finalizer; the trailing throw will escape."); Type guard
static bool IsExpectedThrow(Exception ex) => ex is ArgumentException ae && ae.Message == "fail";
Try / catch
try
{
instance.Method(str);
}
catch (ArgumentException ex) when (ex.Message == "fail")
{
// expected: last-IL throw consumed here if no finalizer patch ran
} Prevention
- Always pair patches of throwing methods with a finalizer (Exception __exception parameter).
- Check Harmony.GetPatchInfo after patching to confirm finalizers were registered.
- Use guard clauses (early return) to skip throw paths when debugging patched methods.
- Write an assertion in tests that the finalizer saw the expected exception message.
- Keep Harmony version in sync with test-asset expectations for finalizer semantics.
When it happens
Trigger: Calling LateThrowClass1.Method(string) with an argument whose Length != 2, either directly or via the generated patch delegate, while HarmonyPatch classes like LateThrowClass_Patch1 are applied. Any code path that invokes this target method during the 'Late throw' test scenario produces it; a finalizer patch that fails to rethrow or swallow it surfaces the raw exception to the caller.
Common situations: Developers encounter this pattern when writing their own Harmony patches against methods whose last IL instruction is a throw: the finalizer (exception handler) inserted by Harmony must handle it, otherwise the exception propagates. Copying this test fixture into user code and calling Method without the expected patch applied also yields the raw throw. It is also hit when a patch author forgets that finalizers run for throws occurring anywhere in the method body, including the tail position.
Understand the failure class
Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.
Related errors
- E0
- 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/5c8a14a050d5e57b.
Report an issue: GitHub.
Appendix: source
Thrown at HarmonyTests/Patching/Assets/Specials.cs:176
{
yield return new CodeInstruction(OpCodes.Call, null);
}
static Exception Cleanup() => null;
}
// -----------------------------------------------------
public class LateThrowClass1
{
[MethodImpl(MethodImplOptions.NoInlining)]
public void Method(string str)
{
if (str.Length == 2)
return;
// this throw is the last IL code before 'ret' in this method
throw new ArgumentException("fail");
}
}
[HarmonyPatch(typeof(LateThrowClass1), nameof(LateThrowClass1.Method))]
public class LateThrowClass_Patch1
{
public static bool prefixCalled = false;
public static bool postfixCalled = false;
static void Prefix() => prefixCalled = true;
static void Postfix() => postfixCalled = true;
}
// -----------------------------------------------------
public class LateThrowClass2
{
View on GitHub (pinned to e7872dc170)